1 /* $OpenBSD: sshconnect.c,v 1.369 2024/12/06 16:21:48 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Code to connect to a remote host, and to perform the client side of the 7 * login (authentication) dialog. 8 * 9 * As far as I am concerned, the code I have written for this software 10 * can be used freely for any purpose. Any derived versions of this 11 * software must be clearly marked as such, and if the derived work is 12 * incompatible with the protocol description in the RFC file, it must be 13 * called by a name other than "ssh" or "Secure Shell". 14 */ 15 16 #include "includes.h" 17 18 #include <sys/types.h> 19 #include <sys/wait.h> 20 #include <sys/stat.h> 21 #include <sys/socket.h> 22 #ifdef HAVE_SYS_TIME_H 23 # include <sys/time.h> 24 #endif 25 26 #include <net/if.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 30 #include <ctype.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <limits.h> 34 #include <netdb.h> 35 #ifdef HAVE_PATHS_H 36 #include <paths.h> 37 #endif 38 #include <pwd.h> 39 #ifdef HAVE_POLL_H 40 #include <poll.h> 41 #endif 42 #include <signal.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <stdarg.h> 46 #include <string.h> 47 #include <unistd.h> 48 #ifdef HAVE_IFADDRS_H 49 # include <ifaddrs.h> 50 #endif 51 52 #include "xmalloc.h" 53 #include "hostfile.h" 54 #include "ssh.h" 55 #include "sshbuf.h" 56 #include "packet.h" 57 #include "sshkey.h" 58 #include "sshconnect.h" 59 #include "log.h" 60 #include "match.h" 61 #include "misc.h" 62 #include "readconf.h" 63 #include "atomicio.h" 64 #include "dns.h" 65 #include "monitor_fdpass.h" 66 #include "ssh2.h" 67 #include "version.h" 68 #include "authfile.h" 69 #include "ssherr.h" 70 #include "authfd.h" 71 #include "kex.h" 72 73 struct sshkey *previous_host_key = NULL; 74 75 static int matching_host_key_dns = 0; 76 77 static pid_t proxy_command_pid = 0; 78 79 /* import */ 80 extern int debug_flag; 81 extern Options options; 82 extern char *__progname; 83 84 static int show_other_keys(struct hostkeys *, struct sshkey *); 85 static void warn_changed_key(struct sshkey *); 86 87 /* Expand a proxy command */ 88 static char * 89 expand_proxy_command(const char *proxy_command, const char *user, 90 const char *host, const char *host_arg, int port) 91 { 92 char *tmp, *ret, strport[NI_MAXSERV]; 93 const char *keyalias = options.host_key_alias ? 94 options.host_key_alias : host_arg; 95 96 snprintf(strport, sizeof strport, "%d", port); 97 xasprintf(&tmp, "exec %s", proxy_command); 98 ret = percent_expand(tmp, 99 "h", host, 100 "k", keyalias, 101 "n", host_arg, 102 "p", strport, 103 "r", options.user, 104 (char *)NULL); 105 free(tmp); 106 return ret; 107 } 108 109 /* 110 * Connect to the given ssh server using a proxy command that passes a 111 * a connected fd back to us. 112 */ 113 static int 114 ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host, 115 const char *host_arg, u_short port, const char *proxy_command) 116 { 117 char *command_string; 118 int sp[2], sock; 119 pid_t pid; 120 char *shell; 121 122 if ((shell = getenv("SHELL")) == NULL) 123 shell = _PATH_BSHELL; 124 125 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) 126 fatal("Could not create socketpair to communicate with " 127 "proxy dialer: %.100s", strerror(errno)); 128 129 command_string = expand_proxy_command(proxy_command, options.user, 130 host, host_arg, port); 131 debug("Executing proxy dialer command: %.500s", command_string); 132 133 /* Fork and execute the proxy command. */ 134 if ((pid = fork()) == 0) { 135 char *argv[10]; 136 137 close(sp[1]); 138 /* Redirect stdin and stdout. */ 139 if (sp[0] != 0) { 140 if (dup2(sp[0], 0) == -1) 141 perror("dup2 stdin"); 142 } 143 if (sp[0] != 1) { 144 if (dup2(sp[0], 1) == -1) 145 perror("dup2 stdout"); 146 } 147 if (sp[0] >= 2) 148 close(sp[0]); 149 150 /* 151 * Stderr is left for non-ControlPersist connections is so 152 * error messages may be printed on the user's terminal. 153 */ 154 if (!debug_flag && options.control_path != NULL && 155 options.control_persist && stdfd_devnull(0, 0, 1) == -1) 156 error_f("stdfd_devnull failed"); 157 158 argv[0] = shell; 159 argv[1] = "-c"; 160 argv[2] = command_string; 161 argv[3] = NULL; 162 163 /* 164 * Execute the proxy command. 165 * Note that we gave up any extra privileges above. 166 */ 167 execv(argv[0], argv); 168 perror(argv[0]); 169 exit(1); 170 } 171 /* Parent. */ 172 if (pid == -1) 173 fatal("fork failed: %.100s", strerror(errno)); 174 close(sp[0]); 175 free(command_string); 176 177 if ((sock = mm_receive_fd(sp[1])) == -1) 178 fatal("proxy dialer did not pass back a connection"); 179 close(sp[1]); 180 181 while (waitpid(pid, NULL, 0) == -1) 182 if (errno != EINTR) 183 fatal("Couldn't wait for child: %s", strerror(errno)); 184 185 /* Set the connection file descriptors. */ 186 if (ssh_packet_set_connection(ssh, sock, sock) == NULL) 187 return -1; /* ssh_packet_set_connection logs error */ 188 189 return 0; 190 } 191 192 /* 193 * Connect to the given ssh server using a proxy command. 194 */ 195 static int 196 ssh_proxy_connect(struct ssh *ssh, const char *host, const char *host_arg, 197 u_short port, const char *proxy_command) 198 { 199 char *command_string; 200 int pin[2], pout[2]; 201 pid_t pid; 202 char *shell; 203 204 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 205 shell = _PATH_BSHELL; 206 207 /* Create pipes for communicating with the proxy. */ 208 if (pipe(pin) == -1 || pipe(pout) == -1) 209 fatal("Could not create pipes to communicate with the proxy: %.100s", 210 strerror(errno)); 211 212 command_string = expand_proxy_command(proxy_command, options.user, 213 host, host_arg, port); 214 debug("Executing proxy command: %.500s", command_string); 215 216 /* Fork and execute the proxy command. */ 217 if ((pid = fork()) == 0) { 218 char *argv[10]; 219 220 /* Redirect stdin and stdout. */ 221 close(pin[1]); 222 if (pin[0] != 0) { 223 if (dup2(pin[0], 0) == -1) 224 perror("dup2 stdin"); 225 close(pin[0]); 226 } 227 close(pout[0]); 228 if (dup2(pout[1], 1) == -1) 229 perror("dup2 stdout"); 230 /* Cannot be 1 because pin allocated two descriptors. */ 231 close(pout[1]); 232 233 /* 234 * Stderr is left for non-ControlPersist connections is so 235 * error messages may be printed on the user's terminal. 236 */ 237 if (!debug_flag && options.control_path != NULL && 238 options.control_persist && stdfd_devnull(0, 0, 1) == -1) 239 error_f("stdfd_devnull failed"); 240 241 argv[0] = shell; 242 argv[1] = "-c"; 243 argv[2] = command_string; 244 argv[3] = NULL; 245 246 /* 247 * Execute the proxy command. Note that we gave up any 248 * extra privileges above. 249 */ 250 ssh_signal(SIGPIPE, SIG_DFL); 251 execv(argv[0], argv); 252 perror(argv[0]); 253 exit(1); 254 } 255 /* Parent. */ 256 if (pid == -1) 257 fatal("fork failed: %.100s", strerror(errno)); 258 else 259 proxy_command_pid = pid; /* save pid to clean up later */ 260 261 /* Close child side of the descriptors. */ 262 close(pin[0]); 263 close(pout[1]); 264 265 /* Free the command name. */ 266 free(command_string); 267 268 /* Set the connection file descriptors. */ 269 if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL) 270 return -1; /* ssh_packet_set_connection logs error */ 271 272 return 0; 273 } 274 275 void 276 ssh_kill_proxy_command(void) 277 { 278 /* 279 * Send SIGHUP to proxy command if used. We don't wait() in 280 * case it hangs and instead rely on init to reap the child 281 */ 282 if (proxy_command_pid > 1) 283 kill(proxy_command_pid, SIGHUP); 284 } 285 286 #ifdef HAVE_IFADDRS_H 287 /* 288 * Search a interface address list (returned from getifaddrs(3)) for an 289 * address that matches the desired address family on the specified interface. 290 * Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure. 291 */ 292 static int 293 check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs, 294 struct sockaddr_storage *resultp, socklen_t *rlenp) 295 { 296 struct sockaddr_in6 *sa6; 297 struct sockaddr_in *sa; 298 struct in6_addr *v6addr; 299 const struct ifaddrs *ifa; 300 int allow_local; 301 302 /* 303 * Prefer addresses that are not loopback or linklocal, but use them 304 * if nothing else matches. 305 */ 306 for (allow_local = 0; allow_local < 2; allow_local++) { 307 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 308 if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL || 309 (ifa->ifa_flags & IFF_UP) == 0 || 310 ifa->ifa_addr->sa_family != af || 311 strcmp(ifa->ifa_name, options.bind_interface) != 0) 312 continue; 313 switch (ifa->ifa_addr->sa_family) { 314 case AF_INET: 315 sa = (struct sockaddr_in *)ifa->ifa_addr; 316 if (!allow_local && sa->sin_addr.s_addr == 317 htonl(INADDR_LOOPBACK)) 318 continue; 319 if (*rlenp < sizeof(struct sockaddr_in)) { 320 error_f("v4 addr doesn't fit"); 321 return -1; 322 } 323 *rlenp = sizeof(struct sockaddr_in); 324 memcpy(resultp, sa, *rlenp); 325 return 0; 326 case AF_INET6: 327 sa6 = (struct sockaddr_in6 *)ifa->ifa_addr; 328 v6addr = &sa6->sin6_addr; 329 if (!allow_local && 330 (IN6_IS_ADDR_LINKLOCAL(v6addr) || 331 IN6_IS_ADDR_LOOPBACK(v6addr))) 332 continue; 333 if (*rlenp < sizeof(struct sockaddr_in6)) { 334 error_f("v6 addr doesn't fit"); 335 return -1; 336 } 337 *rlenp = sizeof(struct sockaddr_in6); 338 memcpy(resultp, sa6, *rlenp); 339 return 0; 340 } 341 } 342 } 343 return -1; 344 } 345 #endif 346 347 /* 348 * Creates a socket for use as the ssh connection. 349 */ 350 static int 351 ssh_create_socket(struct addrinfo *ai) 352 { 353 int sock, r; 354 struct sockaddr_storage bindaddr; 355 socklen_t bindaddrlen = 0; 356 struct addrinfo hints, *res = NULL; 357 #ifdef HAVE_IFADDRS_H 358 struct ifaddrs *ifaddrs = NULL; 359 #endif 360 char ntop[NI_MAXHOST]; 361 362 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 363 if (sock == -1) { 364 error("socket: %s", strerror(errno)); 365 return -1; 366 } 367 (void)fcntl(sock, F_SETFD, FD_CLOEXEC); 368 369 /* Use interactive QOS (if specified) until authentication completed */ 370 if (options.ip_qos_interactive != INT_MAX) 371 set_sock_tos(sock, options.ip_qos_interactive); 372 373 /* Bind the socket to an alternative local IP address */ 374 if (options.bind_address == NULL && options.bind_interface == NULL) 375 return sock; 376 377 if (options.bind_address != NULL) { 378 memset(&hints, 0, sizeof(hints)); 379 hints.ai_family = ai->ai_family; 380 hints.ai_socktype = ai->ai_socktype; 381 hints.ai_protocol = ai->ai_protocol; 382 hints.ai_flags = AI_PASSIVE; 383 if ((r = getaddrinfo(options.bind_address, NULL, 384 &hints, &res)) != 0) { 385 error("getaddrinfo: %s: %s", options.bind_address, 386 ssh_gai_strerror(r)); 387 goto fail; 388 } 389 if (res == NULL) { 390 error("getaddrinfo: no addrs"); 391 goto fail; 392 } 393 memcpy(&bindaddr, res->ai_addr, res->ai_addrlen); 394 bindaddrlen = res->ai_addrlen; 395 } else if (options.bind_interface != NULL) { 396 #ifdef HAVE_IFADDRS_H 397 if ((r = getifaddrs(&ifaddrs)) != 0) { 398 error("getifaddrs: %s: %s", options.bind_interface, 399 strerror(errno)); 400 goto fail; 401 } 402 bindaddrlen = sizeof(bindaddr); 403 if (check_ifaddrs(options.bind_interface, ai->ai_family, 404 ifaddrs, &bindaddr, &bindaddrlen) != 0) { 405 logit("getifaddrs: %s: no suitable addresses", 406 options.bind_interface); 407 goto fail; 408 } 409 #else 410 error("BindInterface not supported on this platform."); 411 #endif 412 } 413 if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen, 414 ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) { 415 error_f("getnameinfo failed: %s", ssh_gai_strerror(r)); 416 goto fail; 417 } 418 if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) { 419 error("bind %s: %s", ntop, strerror(errno)); 420 goto fail; 421 } 422 debug_f("bound to %s", ntop); 423 /* success */ 424 goto out; 425 fail: 426 close(sock); 427 sock = -1; 428 out: 429 if (res != NULL) 430 freeaddrinfo(res); 431 #ifdef HAVE_IFADDRS_H 432 if (ifaddrs != NULL) 433 freeifaddrs(ifaddrs); 434 #endif 435 return sock; 436 } 437 438 /* 439 * Opens a TCP/IP connection to the remote server on the given host. 440 * The address of the remote host will be returned in hostaddr. 441 * If port is 0, the default port will be used. 442 * Connection_attempts specifies the maximum number of tries (one per 443 * second). If proxy_command is non-NULL, it specifies the command (with %h 444 * and %p substituted for host and port, respectively) to use to contact 445 * the daemon. 446 */ 447 static int 448 ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop, 449 struct sockaddr_storage *hostaddr, u_short port, int connection_attempts, 450 int *timeout_ms, int want_keepalive) 451 { 452 int on = 1, saved_timeout_ms = *timeout_ms; 453 int oerrno, sock = -1, attempt; 454 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 455 struct addrinfo *ai; 456 457 debug3_f("entering"); 458 memset(ntop, 0, sizeof(ntop)); 459 memset(strport, 0, sizeof(strport)); 460 461 int inet_supported = feature_present("inet"); 462 int inet6_supported = feature_present("inet6"); 463 for (attempt = 0; attempt < connection_attempts; attempt++) { 464 if (attempt > 0) { 465 /* Sleep a moment before retrying. */ 466 sleep(1); 467 debug("Trying again..."); 468 } 469 /* 470 * Loop through addresses for this host, and try each one in 471 * sequence until the connection succeeds. 472 */ 473 for (ai = aitop; ai; ai = ai->ai_next) { 474 if (ai->ai_family != AF_INET && 475 ai->ai_family != AF_INET6) { 476 errno = EAFNOSUPPORT; 477 continue; 478 } 479 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 480 ntop, sizeof(ntop), strport, sizeof(strport), 481 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 482 oerrno = errno; 483 error_f("getnameinfo failed"); 484 errno = oerrno; 485 continue; 486 } 487 if ((ai->ai_family == AF_INET && !inet_supported) || 488 (ai->ai_family == AF_INET6 && !inet6_supported)) { 489 debug2_f("skipping address [%s]:%s: " 490 "unsupported address family", ntop, strport); 491 errno = EAFNOSUPPORT; 492 continue; 493 } 494 if (options.address_family != AF_UNSPEC && 495 ai->ai_family != options.address_family) { 496 debug2_f("skipping address [%s]:%s: " 497 "wrong address family", ntop, strport); 498 errno = EAFNOSUPPORT; 499 continue; 500 } 501 502 debug("Connecting to %.200s [%.100s] port %s.", 503 host, ntop, strport); 504 505 /* Create a socket for connecting. */ 506 sock = ssh_create_socket(ai); 507 if (sock < 0) { 508 /* Any error is already output */ 509 errno = 0; 510 continue; 511 } 512 513 *timeout_ms = saved_timeout_ms; 514 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 515 timeout_ms) >= 0) { 516 /* Successful connection. */ 517 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 518 break; 519 } else { 520 oerrno = errno; 521 debug("connect to address %s port %s: %s", 522 ntop, strport, strerror(errno)); 523 close(sock); 524 sock = -1; 525 errno = oerrno; 526 } 527 } 528 if (sock != -1) 529 break; /* Successful connection. */ 530 } 531 532 /* Return failure if we didn't get a successful connection. */ 533 if (sock == -1) { 534 error("ssh: connect to host %s port %s: %s", 535 host, strport, errno == 0 ? "failure" : strerror(errno)); 536 return -1; 537 } 538 539 debug("Connection established."); 540 541 /* Set SO_KEEPALIVE if requested. */ 542 if (want_keepalive && 543 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 544 sizeof(on)) == -1) 545 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 546 547 /* Set the connection. */ 548 if (ssh_packet_set_connection(ssh, sock, sock) == NULL) 549 return -1; /* ssh_packet_set_connection logs error */ 550 551 return 0; 552 } 553 554 int 555 ssh_connect(struct ssh *ssh, const char *host, const char *host_arg, 556 struct addrinfo *addrs, struct sockaddr_storage *hostaddr, u_short port, 557 int connection_attempts, int *timeout_ms, int want_keepalive) 558 { 559 int in, out; 560 561 if (options.proxy_command == NULL) { 562 return ssh_connect_direct(ssh, host, addrs, hostaddr, port, 563 connection_attempts, timeout_ms, want_keepalive); 564 } else if (strcmp(options.proxy_command, "-") == 0) { 565 if ((in = dup(STDIN_FILENO)) == -1 || 566 (out = dup(STDOUT_FILENO)) == -1) { 567 if (in >= 0) 568 close(in); 569 error_f("dup() in/out failed"); 570 return -1; /* ssh_packet_set_connection logs error */ 571 } 572 if ((ssh_packet_set_connection(ssh, in, out)) == NULL) 573 return -1; /* ssh_packet_set_connection logs error */ 574 return 0; 575 } else if (options.proxy_use_fdpass) { 576 return ssh_proxy_fdpass_connect(ssh, host, host_arg, port, 577 options.proxy_command); 578 } 579 return ssh_proxy_connect(ssh, host, host_arg, port, 580 options.proxy_command); 581 } 582 583 /* defaults to 'no' */ 584 static int 585 confirm(const char *prompt, const char *fingerprint) 586 { 587 const char *msg, *again = "Please type 'yes' or 'no': "; 588 const char *again_fp = "Please type 'yes', 'no' or the fingerprint: "; 589 char *p, *cp; 590 int ret = -1; 591 592 if (options.batch_mode) 593 return 0; 594 for (msg = prompt;;msg = fingerprint ? again_fp : again) { 595 cp = p = read_passphrase(msg, RP_ECHO); 596 if (p == NULL) 597 return 0; 598 p += strspn(p, " \t"); /* skip leading whitespace */ 599 p[strcspn(p, " \t\n")] = '\0'; /* remove trailing whitespace */ 600 if (p[0] == '\0' || strcasecmp(p, "no") == 0) 601 ret = 0; 602 else if (strcasecmp(p, "yes") == 0 || (fingerprint != NULL && 603 strcmp(p, fingerprint) == 0)) 604 ret = 1; 605 free(cp); 606 if (ret != -1) 607 return ret; 608 } 609 } 610 611 static int 612 sockaddr_is_local(struct sockaddr *hostaddr) 613 { 614 switch (hostaddr->sa_family) { 615 case AF_INET: 616 return (ntohl(((struct sockaddr_in *)hostaddr)-> 617 sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 618 case AF_INET6: 619 return IN6_IS_ADDR_LOOPBACK( 620 &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 621 default: 622 return 0; 623 } 624 } 625 626 /* 627 * Prepare the hostname and ip address strings that are used to lookup 628 * host keys in known_hosts files. These may have a port number appended. 629 */ 630 void 631 get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, 632 u_short port, char **hostfile_hostname, char **hostfile_ipaddr) 633 { 634 char ntop[NI_MAXHOST]; 635 socklen_t addrlen; 636 637 switch (hostaddr == NULL ? -1 : hostaddr->sa_family) { 638 case -1: 639 addrlen = 0; 640 break; 641 case AF_INET: 642 addrlen = sizeof(struct sockaddr_in); 643 break; 644 case AF_INET6: 645 addrlen = sizeof(struct sockaddr_in6); 646 break; 647 default: 648 addrlen = sizeof(struct sockaddr); 649 break; 650 } 651 652 /* 653 * We don't have the remote ip-address for connections 654 * using a proxy command 655 */ 656 if (hostfile_ipaddr != NULL) { 657 if (options.proxy_command == NULL) { 658 if (getnameinfo(hostaddr, addrlen, 659 ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) 660 fatal_f("getnameinfo failed"); 661 *hostfile_ipaddr = put_host_port(ntop, port); 662 } else { 663 *hostfile_ipaddr = xstrdup("<no hostip for proxy " 664 "command>"); 665 } 666 } 667 668 /* 669 * Allow the user to record the key under a different name or 670 * differentiate a non-standard port. This is useful for ssh 671 * tunneling over forwarded connections or if you run multiple 672 * sshd's on different ports on the same machine. 673 */ 674 if (hostfile_hostname != NULL) { 675 if (options.host_key_alias != NULL) { 676 *hostfile_hostname = xstrdup(options.host_key_alias); 677 debug("using hostkeyalias: %s", *hostfile_hostname); 678 } else { 679 *hostfile_hostname = put_host_port(hostname, port); 680 } 681 } 682 } 683 684 /* returns non-zero if path appears in hostfiles, or 0 if not. */ 685 static int 686 path_in_hostfiles(const char *path, char **hostfiles, u_int num_hostfiles) 687 { 688 u_int i; 689 690 for (i = 0; i < num_hostfiles; i++) { 691 if (strcmp(path, hostfiles[i]) == 0) 692 return 1; 693 } 694 return 0; 695 } 696 697 struct find_by_key_ctx { 698 const char *host, *ip; 699 const struct sshkey *key; 700 char **names; 701 u_int nnames; 702 }; 703 704 /* Try to replace home directory prefix (per $HOME) with a ~/ sequence */ 705 static char * 706 try_tilde_unexpand(const char *path) 707 { 708 char *home, *ret = NULL; 709 size_t l; 710 711 if (*path != '/') 712 return xstrdup(path); 713 if ((home = getenv("HOME")) == NULL || (l = strlen(home)) == 0) 714 return xstrdup(path); 715 if (strncmp(path, home, l) != 0) 716 return xstrdup(path); 717 /* 718 * ensure we have matched on a path boundary: either the $HOME that 719 * we just compared ends with a '/' or the next character of the path 720 * must be a '/'. 721 */ 722 if (home[l - 1] != '/' && path[l] != '/') 723 return xstrdup(path); 724 if (path[l] == '/') 725 l++; 726 xasprintf(&ret, "~/%s", path + l); 727 return ret; 728 } 729 730 /* 731 * Returns non-zero if the key is accepted by HostkeyAlgorithms. 732 * Made slightly less trivial by the multiple RSA signature algorithm names. 733 */ 734 int 735 hostkey_accepted_by_hostkeyalgs(const struct sshkey *key) 736 { 737 const char *ktype = sshkey_ssh_name(key); 738 const char *hostkeyalgs = options.hostkeyalgorithms; 739 740 if (key->type == KEY_UNSPEC) 741 return 0; 742 if (key->type == KEY_RSA && 743 (match_pattern_list("rsa-sha2-256", hostkeyalgs, 0) == 1 || 744 match_pattern_list("rsa-sha2-512", hostkeyalgs, 0) == 1)) 745 return 1; 746 if (key->type == KEY_RSA_CERT && 747 (match_pattern_list("rsa-sha2-512-cert-v01@openssh.com", hostkeyalgs, 0) == 1 || 748 match_pattern_list("rsa-sha2-256-cert-v01@openssh.com", hostkeyalgs, 0) == 1)) 749 return 1; 750 return match_pattern_list(ktype, hostkeyalgs, 0) == 1; 751 } 752 753 static int 754 hostkeys_find_by_key_cb(struct hostkey_foreach_line *l, void *_ctx) 755 { 756 struct find_by_key_ctx *ctx = (struct find_by_key_ctx *)_ctx; 757 char *path; 758 759 /* we are looking for keys with names that *do not* match */ 760 if ((l->match & HKF_MATCH_HOST) != 0) 761 return 0; 762 /* not interested in marker lines */ 763 if (l->marker != MRK_NONE) 764 return 0; 765 /* we are only interested in exact key matches */ 766 if (l->key == NULL || !sshkey_equal(ctx->key, l->key)) 767 return 0; 768 path = try_tilde_unexpand(l->path); 769 debug_f("found matching key in %s:%lu", path, l->linenum); 770 ctx->names = xrecallocarray(ctx->names, 771 ctx->nnames, ctx->nnames + 1, sizeof(*ctx->names)); 772 xasprintf(&ctx->names[ctx->nnames], "%s:%lu: %s", path, l->linenum, 773 strncmp(l->hosts, HASH_MAGIC, strlen(HASH_MAGIC)) == 0 ? 774 "[hashed name]" : l->hosts); 775 ctx->nnames++; 776 free(path); 777 return 0; 778 } 779 780 static int 781 hostkeys_find_by_key_hostfile(const char *file, const char *which, 782 struct find_by_key_ctx *ctx) 783 { 784 int r; 785 786 debug3_f("trying %s hostfile \"%s\"", which, file); 787 if ((r = hostkeys_foreach(file, hostkeys_find_by_key_cb, ctx, 788 ctx->host, ctx->ip, HKF_WANT_PARSE_KEY, 0)) != 0) { 789 if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { 790 debug_f("hostkeys file %s does not exist", file); 791 return 0; 792 } 793 error_fr(r, "hostkeys_foreach failed for %s", file); 794 return r; 795 } 796 return 0; 797 } 798 799 /* 800 * Find 'key' in known hosts file(s) that do not match host/ip. 801 * Used to display also-known-as information for previously-unseen hostkeys. 802 */ 803 static void 804 hostkeys_find_by_key(const char *host, const char *ip, const struct sshkey *key, 805 char **user_hostfiles, u_int num_user_hostfiles, 806 char **system_hostfiles, u_int num_system_hostfiles, 807 char ***names, u_int *nnames) 808 { 809 struct find_by_key_ctx ctx = {0, 0, 0, 0, 0}; 810 u_int i; 811 812 *names = NULL; 813 *nnames = 0; 814 815 if (key == NULL || sshkey_is_cert(key)) 816 return; 817 818 ctx.host = host; 819 ctx.ip = ip; 820 ctx.key = key; 821 822 for (i = 0; i < num_user_hostfiles; i++) { 823 if (hostkeys_find_by_key_hostfile(user_hostfiles[i], 824 "user", &ctx) != 0) 825 goto fail; 826 } 827 for (i = 0; i < num_system_hostfiles; i++) { 828 if (hostkeys_find_by_key_hostfile(system_hostfiles[i], 829 "system", &ctx) != 0) 830 goto fail; 831 } 832 /* success */ 833 *names = ctx.names; 834 *nnames = ctx.nnames; 835 ctx.names = NULL; 836 ctx.nnames = 0; 837 return; 838 fail: 839 for (i = 0; i < ctx.nnames; i++) 840 free(ctx.names[i]); 841 free(ctx.names); 842 } 843 844 #define MAX_OTHER_NAMES 8 /* Maximum number of names to list */ 845 static char * 846 other_hostkeys_message(const char *host, const char *ip, 847 const struct sshkey *key, 848 char **user_hostfiles, u_int num_user_hostfiles, 849 char **system_hostfiles, u_int num_system_hostfiles) 850 { 851 char *ret = NULL, **othernames = NULL; 852 u_int i, n, num_othernames = 0; 853 854 hostkeys_find_by_key(host, ip, key, 855 user_hostfiles, num_user_hostfiles, 856 system_hostfiles, num_system_hostfiles, 857 &othernames, &num_othernames); 858 if (num_othernames == 0) 859 return xstrdup("This key is not known by any other names."); 860 861 xasprintf(&ret, "This host key is known by the following other " 862 "names/addresses:"); 863 864 n = num_othernames; 865 if (n > MAX_OTHER_NAMES) 866 n = MAX_OTHER_NAMES; 867 for (i = 0; i < n; i++) { 868 xextendf(&ret, "\n", " %s", othernames[i]); 869 } 870 if (n < num_othernames) { 871 xextendf(&ret, "\n", " (%d additional names omitted)", 872 num_othernames - n); 873 } 874 for (i = 0; i < num_othernames; i++) 875 free(othernames[i]); 876 free(othernames); 877 return ret; 878 } 879 880 void 881 load_hostkeys_command(struct hostkeys *hostkeys, const char *command_template, 882 const char *invocation, const struct ssh_conn_info *cinfo, 883 const struct sshkey *host_key, const char *hostfile_hostname) 884 { 885 int r, i, ac = 0; 886 char *key_fp = NULL, *keytext = NULL, *tmp; 887 char *command = NULL, *tag = NULL, **av = NULL; 888 FILE *f = NULL; 889 pid_t pid; 890 void (*osigchld)(int); 891 892 xasprintf(&tag, "KnownHostsCommand-%s", invocation); 893 894 if (host_key != NULL) { 895 if ((key_fp = sshkey_fingerprint(host_key, 896 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 897 fatal_f("sshkey_fingerprint failed"); 898 if ((r = sshkey_to_base64(host_key, &keytext)) != 0) 899 fatal_fr(r, "sshkey_to_base64 failed"); 900 } 901 /* 902 * NB. all returns later this function should go via "out" to 903 * ensure the original SIGCHLD handler is restored properly. 904 */ 905 osigchld = ssh_signal(SIGCHLD, SIG_DFL); 906 907 /* Turn the command into an argument vector */ 908 if (argv_split(command_template, &ac, &av, 0) != 0) { 909 error("%s \"%s\" contains invalid quotes", tag, 910 command_template); 911 goto out; 912 } 913 if (ac == 0) { 914 error("%s \"%s\" yielded no arguments", tag, 915 command_template); 916 goto out; 917 } 918 for (i = 1; i < ac; i++) { 919 tmp = percent_dollar_expand(av[i], 920 DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo), 921 "H", hostfile_hostname, 922 "I", invocation, 923 "t", host_key == NULL ? "NONE" : sshkey_ssh_name(host_key), 924 "f", key_fp == NULL ? "NONE" : key_fp, 925 "K", keytext == NULL ? "NONE" : keytext, 926 (char *)NULL); 927 if (tmp == NULL) 928 fatal_f("percent_expand failed"); 929 free(av[i]); 930 av[i] = tmp; 931 } 932 /* Prepare a printable command for logs, etc. */ 933 command = argv_assemble(ac, av); 934 935 if ((pid = subprocess(tag, command, ac, av, &f, 936 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH| 937 SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0) 938 goto out; 939 940 load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1); 941 942 if (exited_cleanly(pid, tag, command, 0) != 0) 943 fatal("KnownHostsCommand failed"); 944 945 out: 946 if (f != NULL) 947 fclose(f); 948 ssh_signal(SIGCHLD, osigchld); 949 for (i = 0; i < ac; i++) 950 free(av[i]); 951 free(av); 952 free(tag); 953 free(command); 954 free(key_fp); 955 free(keytext); 956 } 957 958 /* 959 * check whether the supplied host key is valid, return -1 if the key 960 * is not valid. user_hostfile[0] will not be updated if 'readonly' is true. 961 */ 962 #define RDRW 0 963 #define RDONLY 1 964 #define ROQUIET 2 965 static int 966 check_host_key(char *hostname, const struct ssh_conn_info *cinfo, 967 struct sockaddr *hostaddr, u_short port, 968 struct sshkey *host_key, int readonly, int clobber_port, 969 char **user_hostfiles, u_int num_user_hostfiles, 970 char **system_hostfiles, u_int num_system_hostfiles, 971 const char *hostfile_command) 972 { 973 HostStatus host_status = -1, ip_status = -1; 974 struct sshkey *raw_key = NULL; 975 char *ip = NULL, *host = NULL; 976 char hostline[1000], *hostp, *fp, *ra; 977 char msg[1024]; 978 const char *type, *fail_reason = NULL; 979 const struct hostkey_entry *host_found = NULL, *ip_found = NULL; 980 int len, cancelled_forwarding = 0, confirmed; 981 int local = sockaddr_is_local(hostaddr); 982 int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0; 983 int hostkey_trusted = 0; /* Known or explicitly accepted by user */ 984 struct hostkeys *host_hostkeys, *ip_hostkeys; 985 u_int i; 986 987 /* 988 * Force accepting of the host key for loopback/localhost. The 989 * problem is that if the home directory is NFS-mounted to multiple 990 * machines, localhost will refer to a different machine in each of 991 * them, and the user will get bogus HOST_CHANGED warnings. This 992 * essentially disables host authentication for localhost; however, 993 * this is probably not a real problem. 994 */ 995 if (options.no_host_authentication_for_localhost == 1 && local && 996 options.host_key_alias == NULL) { 997 debug("Forcing accepting of host key for " 998 "loopback/localhost."); 999 options.update_hostkeys = 0; 1000 return 0; 1001 } 1002 1003 /* 1004 * Don't ever try to write an invalid name to a known hosts file. 1005 * Note: do this before get_hostfile_hostname_ipaddr() to catch 1006 * '[' or ']' in the name before they are added. 1007 */ 1008 if (strcspn(hostname, "@?*#[]|'\'\"\\") != strlen(hostname)) { 1009 debug_f("invalid hostname \"%s\"; will not record: %s", 1010 hostname, fail_reason); 1011 readonly = RDONLY; 1012 } 1013 1014 /* 1015 * Prepare the hostname and address strings used for hostkey lookup. 1016 * In some cases, these will have a port number appended. 1017 */ 1018 get_hostfile_hostname_ipaddr(hostname, hostaddr, 1019 clobber_port ? 0 : port, &host, &ip); 1020 1021 /* 1022 * Turn off check_host_ip if the connection is to localhost, via proxy 1023 * command or if we don't have a hostname to compare with 1024 */ 1025 if (options.check_host_ip && (local || 1026 strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) 1027 options.check_host_ip = 0; 1028 1029 host_hostkeys = init_hostkeys(); 1030 for (i = 0; i < num_user_hostfiles; i++) 1031 load_hostkeys(host_hostkeys, host, user_hostfiles[i], 0); 1032 for (i = 0; i < num_system_hostfiles; i++) 1033 load_hostkeys(host_hostkeys, host, system_hostfiles[i], 0); 1034 if (hostfile_command != NULL && !clobber_port) { 1035 load_hostkeys_command(host_hostkeys, hostfile_command, 1036 "HOSTNAME", cinfo, host_key, host); 1037 } 1038 1039 ip_hostkeys = NULL; 1040 if (!want_cert && options.check_host_ip) { 1041 ip_hostkeys = init_hostkeys(); 1042 for (i = 0; i < num_user_hostfiles; i++) 1043 load_hostkeys(ip_hostkeys, ip, user_hostfiles[i], 0); 1044 for (i = 0; i < num_system_hostfiles; i++) 1045 load_hostkeys(ip_hostkeys, ip, system_hostfiles[i], 0); 1046 if (hostfile_command != NULL && !clobber_port) { 1047 load_hostkeys_command(ip_hostkeys, hostfile_command, 1048 "ADDRESS", cinfo, host_key, ip); 1049 } 1050 } 1051 1052 retry: 1053 if (!hostkey_accepted_by_hostkeyalgs(host_key)) { 1054 error("host key %s not permitted by HostkeyAlgorithms", 1055 sshkey_ssh_name(host_key)); 1056 goto fail; 1057 } 1058 1059 /* Reload these as they may have changed on cert->key downgrade */ 1060 want_cert = sshkey_is_cert(host_key); 1061 type = sshkey_type(host_key); 1062 1063 /* 1064 * Check if the host key is present in the user's list of known 1065 * hosts or in the systemwide list. 1066 */ 1067 host_status = check_key_in_hostkeys(host_hostkeys, host_key, 1068 &host_found); 1069 1070 /* 1071 * If there are no hostfiles, or if the hostkey was found via 1072 * KnownHostsCommand, then don't try to touch the disk. 1073 */ 1074 if (!readonly && (num_user_hostfiles == 0 || 1075 (host_found != NULL && host_found->note != 0))) 1076 readonly = RDONLY; 1077 1078 /* 1079 * Also perform check for the ip address, skip the check if we are 1080 * localhost, looking for a certificate, or the hostname was an ip 1081 * address to begin with. 1082 */ 1083 if (!want_cert && ip_hostkeys != NULL) { 1084 ip_status = check_key_in_hostkeys(ip_hostkeys, host_key, 1085 &ip_found); 1086 if (host_status == HOST_CHANGED && 1087 (ip_status != HOST_CHANGED || 1088 (ip_found != NULL && 1089 !sshkey_equal(ip_found->key, host_found->key)))) 1090 host_ip_differ = 1; 1091 } else 1092 ip_status = host_status; 1093 1094 switch (host_status) { 1095 case HOST_OK: 1096 /* The host is known and the key matches. */ 1097 debug("Host '%.200s' is known and matches the %s host %s.", 1098 host, type, want_cert ? "certificate" : "key"); 1099 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", 1100 host_found->file, host_found->line); 1101 if (want_cert) { 1102 if (sshkey_cert_check_host(host_key, 1103 options.host_key_alias == NULL ? 1104 hostname : options.host_key_alias, 0, 1105 options.ca_sign_algorithms, &fail_reason) != 0) { 1106 error("%s", fail_reason); 1107 goto fail; 1108 } 1109 /* 1110 * Do not attempt hostkey update if a certificate was 1111 * successfully matched. 1112 */ 1113 if (options.update_hostkeys != 0) { 1114 options.update_hostkeys = 0; 1115 debug3_f("certificate host key in use; " 1116 "disabling UpdateHostkeys"); 1117 } 1118 } 1119 /* Turn off UpdateHostkeys if key was in system known_hosts */ 1120 if (options.update_hostkeys != 0 && 1121 (path_in_hostfiles(host_found->file, 1122 system_hostfiles, num_system_hostfiles) || 1123 (ip_status == HOST_OK && ip_found != NULL && 1124 path_in_hostfiles(ip_found->file, 1125 system_hostfiles, num_system_hostfiles)))) { 1126 options.update_hostkeys = 0; 1127 debug3_f("host key found in GlobalKnownHostsFile; " 1128 "disabling UpdateHostkeys"); 1129 } 1130 if (options.update_hostkeys != 0 && host_found->note) { 1131 options.update_hostkeys = 0; 1132 debug3_f("host key found via KnownHostsCommand; " 1133 "disabling UpdateHostkeys"); 1134 } 1135 if (options.check_host_ip && ip_status == HOST_NEW) { 1136 if (readonly || want_cert) 1137 logit("%s host key for IP address " 1138 "'%.128s' not in list of known hosts.", 1139 type, ip); 1140 else if (!add_host_to_hostfile(user_hostfiles[0], ip, 1141 host_key, options.hash_known_hosts)) 1142 logit("Failed to add the %s host key for IP " 1143 "address '%.128s' to the list of known " 1144 "hosts (%.500s).", type, ip, 1145 user_hostfiles[0]); 1146 else 1147 logit("Warning: Permanently added the %s host " 1148 "key for IP address '%.128s' to the list " 1149 "of known hosts.", type, ip); 1150 } else if (options.visual_host_key) { 1151 fp = sshkey_fingerprint(host_key, 1152 options.fingerprint_hash, SSH_FP_DEFAULT); 1153 ra = sshkey_fingerprint(host_key, 1154 options.fingerprint_hash, SSH_FP_RANDOMART); 1155 if (fp == NULL || ra == NULL) 1156 fatal_f("sshkey_fingerprint failed"); 1157 logit("Host key fingerprint is %s\n%s", fp, ra); 1158 free(ra); 1159 free(fp); 1160 } 1161 hostkey_trusted = 1; 1162 break; 1163 case HOST_NEW: 1164 if (options.host_key_alias == NULL && port != 0 && 1165 port != SSH_DEFAULT_PORT && !clobber_port) { 1166 debug("checking without port identifier"); 1167 if (check_host_key(hostname, cinfo, hostaddr, 0, 1168 host_key, ROQUIET, 1, 1169 user_hostfiles, num_user_hostfiles, 1170 system_hostfiles, num_system_hostfiles, 1171 hostfile_command) == 0) { 1172 debug("found matching key w/out port"); 1173 break; 1174 } 1175 } 1176 if (readonly || want_cert) 1177 goto fail; 1178 /* The host is new. */ 1179 if (options.strict_host_key_checking == 1180 SSH_STRICT_HOSTKEY_YES) { 1181 /* 1182 * User has requested strict host key checking. We 1183 * will not add the host key automatically. The only 1184 * alternative left is to abort. 1185 */ 1186 error("No %s host key is known for %.200s and you " 1187 "have requested strict checking.", type, host); 1188 goto fail; 1189 } else if (options.strict_host_key_checking == 1190 SSH_STRICT_HOSTKEY_ASK) { 1191 char *msg1 = NULL, *msg2 = NULL; 1192 1193 xasprintf(&msg1, "The authenticity of host " 1194 "'%.200s (%s)' can't be established", host, ip); 1195 1196 if (show_other_keys(host_hostkeys, host_key)) { 1197 xextendf(&msg1, "\n", "but keys of different " 1198 "type are already known for this host."); 1199 } else 1200 xextendf(&msg1, "", "."); 1201 1202 fp = sshkey_fingerprint(host_key, 1203 options.fingerprint_hash, SSH_FP_DEFAULT); 1204 ra = sshkey_fingerprint(host_key, 1205 options.fingerprint_hash, SSH_FP_RANDOMART); 1206 if (fp == NULL || ra == NULL) 1207 fatal_f("sshkey_fingerprint failed"); 1208 xextendf(&msg1, "\n", "%s key fingerprint is %s.", 1209 type, fp); 1210 if (options.visual_host_key) 1211 xextendf(&msg1, "\n", "%s", ra); 1212 if (options.verify_host_key_dns) { 1213 xextendf(&msg1, "\n", 1214 "%s host key fingerprint found in DNS.", 1215 matching_host_key_dns ? 1216 "Matching" : "No matching"); 1217 } 1218 /* msg2 informs for other names matching this key */ 1219 if ((msg2 = other_hostkeys_message(host, ip, host_key, 1220 user_hostfiles, num_user_hostfiles, 1221 system_hostfiles, num_system_hostfiles)) != NULL) 1222 xextendf(&msg1, "\n", "%s", msg2); 1223 1224 xextendf(&msg1, "\n", 1225 "Are you sure you want to continue connecting " 1226 "(yes/no/[fingerprint])? "); 1227 1228 confirmed = confirm(msg1, fp); 1229 free(ra); 1230 free(fp); 1231 free(msg1); 1232 free(msg2); 1233 if (!confirmed) 1234 goto fail; 1235 hostkey_trusted = 1; /* user explicitly confirmed */ 1236 } 1237 /* 1238 * If in "new" or "off" strict mode, add the key automatically 1239 * to the local known_hosts file. 1240 */ 1241 if (options.check_host_ip && ip_status == HOST_NEW) { 1242 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 1243 hostp = hostline; 1244 if (options.hash_known_hosts) { 1245 /* Add hash of host and IP separately */ 1246 r = add_host_to_hostfile(user_hostfiles[0], 1247 host, host_key, options.hash_known_hosts) && 1248 add_host_to_hostfile(user_hostfiles[0], ip, 1249 host_key, options.hash_known_hosts); 1250 } else { 1251 /* Add unhashed "host,ip" */ 1252 r = add_host_to_hostfile(user_hostfiles[0], 1253 hostline, host_key, 1254 options.hash_known_hosts); 1255 } 1256 } else { 1257 r = add_host_to_hostfile(user_hostfiles[0], host, 1258 host_key, options.hash_known_hosts); 1259 hostp = host; 1260 } 1261 1262 if (!r) 1263 logit("Failed to add the host to the list of known " 1264 "hosts (%.500s).", user_hostfiles[0]); 1265 else 1266 logit("Warning: Permanently added '%.200s' (%s) to the " 1267 "list of known hosts.", hostp, type); 1268 break; 1269 case HOST_REVOKED: 1270 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1271 error("@ WARNING: REVOKED HOST KEY DETECTED! @"); 1272 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1273 error("The %s host key for %s is marked as revoked.", type, host); 1274 error("This could mean that a stolen key is being used to"); 1275 error("impersonate this host."); 1276 1277 /* 1278 * If strict host key checking is in use, the user will have 1279 * to edit the key manually and we can only abort. 1280 */ 1281 if (options.strict_host_key_checking != 1282 SSH_STRICT_HOSTKEY_OFF) { 1283 error("%s host key for %.200s was revoked and you have " 1284 "requested strict checking.", type, host); 1285 goto fail; 1286 } 1287 goto continue_unsafe; 1288 1289 case HOST_CHANGED: 1290 if (want_cert) { 1291 /* 1292 * This is only a debug() since it is valid to have 1293 * CAs with wildcard DNS matches that don't match 1294 * all hosts that one might visit. 1295 */ 1296 debug("Host certificate authority does not " 1297 "match %s in %s:%lu", CA_MARKER, 1298 host_found->file, host_found->line); 1299 goto fail; 1300 } 1301 if (readonly == ROQUIET) 1302 goto fail; 1303 if (options.check_host_ip && host_ip_differ) { 1304 char *key_msg; 1305 if (ip_status == HOST_NEW) 1306 key_msg = "is unknown"; 1307 else if (ip_status == HOST_OK) 1308 key_msg = "is unchanged"; 1309 else 1310 key_msg = "has a different value"; 1311 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1312 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 1313 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1314 error("The %s host key for %s has changed,", type, host); 1315 error("and the key for the corresponding IP address %s", ip); 1316 error("%s. This could either mean that", key_msg); 1317 error("DNS SPOOFING is happening or the IP address for the host"); 1318 error("and its host key have changed at the same time."); 1319 if (ip_status != HOST_NEW) 1320 error("Offending key for IP in %s:%lu", 1321 ip_found->file, ip_found->line); 1322 } 1323 /* The host key has changed. */ 1324 warn_changed_key(host_key); 1325 if (num_user_hostfiles > 0 || num_system_hostfiles > 0) { 1326 error("Add correct host key in %.100s to get rid " 1327 "of this message.", num_user_hostfiles > 0 ? 1328 user_hostfiles[0] : system_hostfiles[0]); 1329 } 1330 error("Offending %s key in %s:%lu", 1331 sshkey_type(host_found->key), 1332 host_found->file, host_found->line); 1333 1334 /* 1335 * If strict host key checking is in use, the user will have 1336 * to edit the key manually and we can only abort. 1337 */ 1338 if (options.strict_host_key_checking != 1339 SSH_STRICT_HOSTKEY_OFF) { 1340 error("Host key for %.200s has changed and you have " 1341 "requested strict checking.", host); 1342 goto fail; 1343 } 1344 1345 continue_unsafe: 1346 /* 1347 * If strict host key checking has not been requested, allow 1348 * the connection but without MITM-able authentication or 1349 * forwarding. 1350 */ 1351 if (options.password_authentication) { 1352 error("Password authentication is disabled to avoid " 1353 "man-in-the-middle attacks."); 1354 options.password_authentication = 0; 1355 cancelled_forwarding = 1; 1356 } 1357 if (options.kbd_interactive_authentication) { 1358 error("Keyboard-interactive authentication is disabled" 1359 " to avoid man-in-the-middle attacks."); 1360 options.kbd_interactive_authentication = 0; 1361 cancelled_forwarding = 1; 1362 } 1363 if (options.forward_agent) { 1364 error("Agent forwarding is disabled to avoid " 1365 "man-in-the-middle attacks."); 1366 options.forward_agent = 0; 1367 cancelled_forwarding = 1; 1368 } 1369 if (options.forward_x11) { 1370 error("X11 forwarding is disabled to avoid " 1371 "man-in-the-middle attacks."); 1372 options.forward_x11 = 0; 1373 cancelled_forwarding = 1; 1374 } 1375 if (options.num_local_forwards > 0 || 1376 options.num_remote_forwards > 0) { 1377 error("Port forwarding is disabled to avoid " 1378 "man-in-the-middle attacks."); 1379 options.num_local_forwards = 1380 options.num_remote_forwards = 0; 1381 cancelled_forwarding = 1; 1382 } 1383 if (options.tun_open != SSH_TUNMODE_NO) { 1384 error("Tunnel forwarding is disabled to avoid " 1385 "man-in-the-middle attacks."); 1386 options.tun_open = SSH_TUNMODE_NO; 1387 cancelled_forwarding = 1; 1388 } 1389 if (options.update_hostkeys != 0) { 1390 error("UpdateHostkeys is disabled because the host " 1391 "key is not trusted."); 1392 options.update_hostkeys = 0; 1393 } 1394 if (options.exit_on_forward_failure && cancelled_forwarding) 1395 fatal("Error: forwarding disabled due to host key " 1396 "check failure"); 1397 1398 /* 1399 * XXX Should permit the user to change to use the new id. 1400 * This could be done by converting the host key to an 1401 * identifying sentence, tell that the host identifies itself 1402 * by that sentence, and ask the user if they wish to 1403 * accept the authentication. 1404 */ 1405 break; 1406 case HOST_FOUND: 1407 fatal("internal error"); 1408 break; 1409 } 1410 1411 if (options.check_host_ip && host_status != HOST_CHANGED && 1412 ip_status == HOST_CHANGED) { 1413 snprintf(msg, sizeof(msg), 1414 "Warning: the %s host key for '%.200s' " 1415 "differs from the key for the IP address '%.128s'" 1416 "\nOffending key for IP in %s:%lu", 1417 type, host, ip, ip_found->file, ip_found->line); 1418 if (host_status == HOST_OK) { 1419 len = strlen(msg); 1420 snprintf(msg + len, sizeof(msg) - len, 1421 "\nMatching host key in %s:%lu", 1422 host_found->file, host_found->line); 1423 } 1424 if (options.strict_host_key_checking == 1425 SSH_STRICT_HOSTKEY_ASK) { 1426 strlcat(msg, "\nAre you sure you want " 1427 "to continue connecting (yes/no)? ", sizeof(msg)); 1428 if (!confirm(msg, NULL)) 1429 goto fail; 1430 } else if (options.strict_host_key_checking != 1431 SSH_STRICT_HOSTKEY_OFF) { 1432 logit("%s", msg); 1433 error("Exiting, you have requested strict checking."); 1434 goto fail; 1435 } else { 1436 logit("%s", msg); 1437 } 1438 } 1439 1440 if (!hostkey_trusted && options.update_hostkeys) { 1441 debug_f("hostkey not known or explicitly trusted: " 1442 "disabling UpdateHostkeys"); 1443 options.update_hostkeys = 0; 1444 } 1445 1446 free(ip); 1447 free(host); 1448 if (host_hostkeys != NULL) 1449 free_hostkeys(host_hostkeys); 1450 if (ip_hostkeys != NULL) 1451 free_hostkeys(ip_hostkeys); 1452 return 0; 1453 1454 fail: 1455 if (want_cert && host_status != HOST_REVOKED) { 1456 /* 1457 * No matching certificate. Downgrade cert to raw key and 1458 * search normally. 1459 */ 1460 debug("No matching CA found. Retry with plain key"); 1461 if ((r = sshkey_from_private(host_key, &raw_key)) != 0) 1462 fatal_fr(r, "decode key"); 1463 if ((r = sshkey_drop_cert(raw_key)) != 0) 1464 fatal_r(r, "Couldn't drop certificate"); 1465 host_key = raw_key; 1466 goto retry; 1467 } 1468 sshkey_free(raw_key); 1469 free(ip); 1470 free(host); 1471 if (host_hostkeys != NULL) 1472 free_hostkeys(host_hostkeys); 1473 if (ip_hostkeys != NULL) 1474 free_hostkeys(ip_hostkeys); 1475 return -1; 1476 } 1477 1478 /* returns 0 if key verifies or -1 if key does NOT verify */ 1479 int 1480 verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key, 1481 const struct ssh_conn_info *cinfo) 1482 { 1483 u_int i; 1484 int r = -1, flags = 0; 1485 char valid[64], *fp = NULL, *cafp = NULL; 1486 struct sshkey *plain = NULL; 1487 1488 if ((fp = sshkey_fingerprint(host_key, 1489 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 1490 error_fr(r, "fingerprint host key"); 1491 r = -1; 1492 goto out; 1493 } 1494 1495 if (sshkey_is_cert(host_key)) { 1496 if ((cafp = sshkey_fingerprint(host_key->cert->signature_key, 1497 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 1498 error_fr(r, "fingerprint CA key"); 1499 r = -1; 1500 goto out; 1501 } 1502 sshkey_format_cert_validity(host_key->cert, 1503 valid, sizeof(valid)); 1504 debug("Server host certificate: %s %s, serial %llu " 1505 "ID \"%s\" CA %s %s valid %s", 1506 sshkey_ssh_name(host_key), fp, 1507 (unsigned long long)host_key->cert->serial, 1508 host_key->cert->key_id, 1509 sshkey_ssh_name(host_key->cert->signature_key), cafp, 1510 valid); 1511 for (i = 0; i < host_key->cert->nprincipals; i++) { 1512 debug2("Server host certificate hostname: %s", 1513 host_key->cert->principals[i]); 1514 } 1515 } else { 1516 debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp); 1517 } 1518 1519 if (sshkey_equal(previous_host_key, host_key)) { 1520 debug2_f("server host key %s %s matches cached key", 1521 sshkey_type(host_key), fp); 1522 r = 0; 1523 goto out; 1524 } 1525 1526 /* Check in RevokedHostKeys file if specified */ 1527 if (options.revoked_host_keys != NULL) { 1528 r = sshkey_check_revoked(host_key, options.revoked_host_keys); 1529 switch (r) { 1530 case 0: 1531 break; /* not revoked */ 1532 case SSH_ERR_KEY_REVOKED: 1533 error("Host key %s %s revoked by file %s", 1534 sshkey_type(host_key), fp, 1535 options.revoked_host_keys); 1536 r = -1; 1537 goto out; 1538 default: 1539 error_r(r, "Error checking host key %s %s in " 1540 "revoked keys file %s", sshkey_type(host_key), 1541 fp, options.revoked_host_keys); 1542 r = -1; 1543 goto out; 1544 } 1545 } 1546 1547 if (options.verify_host_key_dns) { 1548 /* 1549 * XXX certs are not yet supported for DNS, so downgrade 1550 * them and try the plain key. 1551 */ 1552 if ((r = sshkey_from_private(host_key, &plain)) != 0) 1553 goto out; 1554 if (sshkey_is_cert(plain)) 1555 sshkey_drop_cert(plain); 1556 if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { 1557 if (flags & DNS_VERIFY_FOUND) { 1558 if (options.verify_host_key_dns == 1 && 1559 flags & DNS_VERIFY_MATCH && 1560 flags & DNS_VERIFY_SECURE) { 1561 r = 0; 1562 goto out; 1563 } 1564 if (flags & DNS_VERIFY_MATCH) { 1565 matching_host_key_dns = 1; 1566 } else { 1567 warn_changed_key(plain); 1568 error("Update the SSHFP RR in DNS " 1569 "with the new host key to get rid " 1570 "of this message."); 1571 } 1572 } 1573 } 1574 } 1575 r = check_host_key(host, cinfo, hostaddr, options.port, host_key, 1576 RDRW, 0, options.user_hostfiles, options.num_user_hostfiles, 1577 options.system_hostfiles, options.num_system_hostfiles, 1578 options.known_hosts_command); 1579 1580 out: 1581 sshkey_free(plain); 1582 free(fp); 1583 free(cafp); 1584 if (r == 0 && host_key != NULL) { 1585 sshkey_free(previous_host_key); 1586 r = sshkey_from_private(host_key, &previous_host_key); 1587 } 1588 1589 return r; 1590 } 1591 1592 /* 1593 * Starts a dialog with the server, and authenticates the current user on the 1594 * server. This does not need any extra privileges. The basic connection 1595 * to the server must already have been established before this is called. 1596 * If login fails, this function prints an error and never returns. 1597 * This function does not require super-user privileges. 1598 */ 1599 void 1600 ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost, 1601 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms, 1602 const struct ssh_conn_info *cinfo) 1603 { 1604 char *host; 1605 char *server_user, *local_user; 1606 int r; 1607 1608 local_user = xstrdup(pw->pw_name); 1609 server_user = options.user ? options.user : local_user; 1610 1611 /* Convert the user-supplied hostname into all lowercase. */ 1612 host = xstrdup(orighost); 1613 lowercase(host); 1614 1615 /* Exchange protocol version identification strings with the server. */ 1616 if ((r = kex_exchange_identification(ssh, timeout_ms, 1617 options.version_addendum)) != 0) 1618 sshpkt_fatal(ssh, r, "banner exchange"); 1619 1620 /* Put the connection into non-blocking mode. */ 1621 ssh_packet_set_nonblocking(ssh); 1622 1623 /* key exchange */ 1624 /* authenticate user */ 1625 debug("Authenticating to %s:%d as '%s'", host, port, server_user); 1626 ssh_kex2(ssh, host, hostaddr, port, cinfo); 1627 ssh_userauth2(ssh, local_user, server_user, host, sensitive); 1628 free(local_user); 1629 free(host); 1630 } 1631 1632 /* print all known host keys for a given host, but skip keys of given type */ 1633 static int 1634 show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) 1635 { 1636 int type[] = { 1637 KEY_RSA, 1638 #ifdef WITH_DSA 1639 KEY_DSA, 1640 #endif 1641 KEY_ECDSA, 1642 KEY_ED25519, 1643 KEY_XMSS, 1644 -1 1645 }; 1646 int i, ret = 0; 1647 char *fp, *ra; 1648 const struct hostkey_entry *found; 1649 1650 for (i = 0; type[i] != -1; i++) { 1651 if (type[i] == key->type) 1652 continue; 1653 if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], 1654 -1, &found)) 1655 continue; 1656 fp = sshkey_fingerprint(found->key, 1657 options.fingerprint_hash, SSH_FP_DEFAULT); 1658 ra = sshkey_fingerprint(found->key, 1659 options.fingerprint_hash, SSH_FP_RANDOMART); 1660 if (fp == NULL || ra == NULL) 1661 fatal_f("sshkey_fingerprint fail"); 1662 logit("WARNING: %s key found for host %s\n" 1663 "in %s:%lu\n" 1664 "%s key fingerprint %s.", 1665 sshkey_type(found->key), 1666 found->host, found->file, found->line, 1667 sshkey_type(found->key), fp); 1668 if (options.visual_host_key) 1669 logit("%s", ra); 1670 free(ra); 1671 free(fp); 1672 ret = 1; 1673 } 1674 return ret; 1675 } 1676 1677 static void 1678 warn_changed_key(struct sshkey *host_key) 1679 { 1680 char *fp; 1681 1682 fp = sshkey_fingerprint(host_key, options.fingerprint_hash, 1683 SSH_FP_DEFAULT); 1684 if (fp == NULL) 1685 fatal_f("sshkey_fingerprint fail"); 1686 1687 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1688 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 1689 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1690 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1691 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1692 error("It is also possible that a host key has just been changed."); 1693 error("The fingerprint for the %s key sent by the remote host is\n%s.", 1694 sshkey_type(host_key), fp); 1695 error("Please contact your system administrator."); 1696 1697 free(fp); 1698 } 1699 1700 /* 1701 * Execute a local command 1702 */ 1703 int 1704 ssh_local_cmd(const char *args) 1705 { 1706 char *shell; 1707 pid_t pid; 1708 int status; 1709 void (*osighand)(int); 1710 1711 if (!options.permit_local_command || 1712 args == NULL || !*args) 1713 return (1); 1714 1715 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 1716 shell = _PATH_BSHELL; 1717 1718 osighand = ssh_signal(SIGCHLD, SIG_DFL); 1719 pid = fork(); 1720 if (pid == 0) { 1721 ssh_signal(SIGPIPE, SIG_DFL); 1722 debug3("Executing %s -c \"%s\"", shell, args); 1723 execl(shell, shell, "-c", args, (char *)NULL); 1724 error("Couldn't execute %s -c \"%s\": %s", 1725 shell, args, strerror(errno)); 1726 _exit(1); 1727 } else if (pid == -1) 1728 fatal("fork failed: %.100s", strerror(errno)); 1729 while (waitpid(pid, &status, 0) == -1) 1730 if (errno != EINTR) 1731 fatal("Couldn't wait for child: %s", strerror(errno)); 1732 ssh_signal(SIGCHLD, osighand); 1733 1734 if (!WIFEXITED(status)) 1735 return (1); 1736 1737 return (WEXITSTATUS(status)); 1738 } 1739 1740 void 1741 maybe_add_key_to_agent(const char *authfile, struct sshkey *private, 1742 const char *comment, const char *passphrase) 1743 { 1744 int auth_sock = -1, r; 1745 const char *skprovider = NULL; 1746 1747 if (options.add_keys_to_agent == 0) 1748 return; 1749 1750 if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { 1751 debug3("no authentication agent, not adding key"); 1752 return; 1753 } 1754 1755 if (options.add_keys_to_agent == 2 && 1756 !ask_permission("Add key %s (%s) to agent?", authfile, comment)) { 1757 debug3("user denied adding this key"); 1758 close(auth_sock); 1759 return; 1760 } 1761 if (sshkey_is_sk(private)) 1762 skprovider = options.sk_provider; 1763 if ((r = ssh_add_identity_constrained(auth_sock, private, 1764 comment == NULL ? authfile : comment, 1765 options.add_keys_to_agent_lifespan, 1766 (options.add_keys_to_agent == 3), 0, skprovider, NULL, 0)) == 0) 1767 debug("identity added to agent: %s", authfile); 1768 else 1769 debug("could not add identity to agent: %s (%d)", authfile, r); 1770 close(auth_sock); 1771 } 1772