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