1 /* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * Code to connect to a remote host, and to perform the client side of the 6 * login (authentication) dialog. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 */ 14 15 #include "includes.h" 16 RCSID("$OpenBSD: sshconnect.c,v 1.156 2004/01/25 03:49:09 djm Exp $"); 17 18 #include <openssl/bn.h> 19 20 #include "ssh.h" 21 #include "xmalloc.h" 22 #include "rsa.h" 23 #include "buffer.h" 24 #include "packet.h" 25 #include "uidswap.h" 26 #include "compat.h" 27 #include "key.h" 28 #include "sshconnect.h" 29 #include "hostfile.h" 30 #include "log.h" 31 #include "readconf.h" 32 #include "atomicio.h" 33 #include "misc.h" 34 #include "readpass.h" 35 36 #include "dns.h" 37 38 char *client_version_string = NULL; 39 char *server_version_string = NULL; 40 41 int matching_host_key_dns = 0; 42 43 /* import */ 44 extern Options options; 45 extern char *__progname; 46 extern uid_t original_real_uid; 47 extern uid_t original_effective_uid; 48 extern pid_t proxy_command_pid; 49 50 #ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ 51 #define INET6_ADDRSTRLEN 46 52 #endif 53 54 static int show_other_keys(const char *, Key *); 55 static void warn_changed_key(Key *); 56 57 /* 58 * Connect to the given ssh server using a proxy command. 59 */ 60 static int 61 ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 62 { 63 Buffer command; 64 const char *cp; 65 char *command_string; 66 int pin[2], pout[2]; 67 pid_t pid; 68 char strport[NI_MAXSERV]; 69 70 /* Convert the port number into a string. */ 71 snprintf(strport, sizeof strport, "%hu", port); 72 73 /* 74 * Build the final command string in the buffer by making the 75 * appropriate substitutions to the given proxy command. 76 * 77 * Use "exec" to avoid "sh -c" processes on some platforms 78 * (e.g. Solaris) 79 */ 80 buffer_init(&command); 81 buffer_append(&command, "exec ", 5); 82 83 for (cp = proxy_command; *cp; cp++) { 84 if (cp[0] == '%' && cp[1] == '%') { 85 buffer_append(&command, "%", 1); 86 cp++; 87 continue; 88 } 89 if (cp[0] == '%' && cp[1] == 'h') { 90 buffer_append(&command, host, strlen(host)); 91 cp++; 92 continue; 93 } 94 if (cp[0] == '%' && cp[1] == 'p') { 95 buffer_append(&command, strport, strlen(strport)); 96 cp++; 97 continue; 98 } 99 buffer_append(&command, cp, 1); 100 } 101 buffer_append(&command, "\0", 1); 102 103 /* Get the final command string. */ 104 command_string = buffer_ptr(&command); 105 106 /* Create pipes for communicating with the proxy. */ 107 if (pipe(pin) < 0 || pipe(pout) < 0) 108 fatal("Could not create pipes to communicate with the proxy: %.100s", 109 strerror(errno)); 110 111 debug("Executing proxy command: %.500s", command_string); 112 113 /* Fork and execute the proxy command. */ 114 if ((pid = fork()) == 0) { 115 char *argv[10]; 116 117 /* Child. Permanently give up superuser privileges. */ 118 seteuid(original_real_uid); 119 setuid(original_real_uid); 120 121 /* Redirect stdin and stdout. */ 122 close(pin[1]); 123 if (pin[0] != 0) { 124 if (dup2(pin[0], 0) < 0) 125 perror("dup2 stdin"); 126 close(pin[0]); 127 } 128 close(pout[0]); 129 if (dup2(pout[1], 1) < 0) 130 perror("dup2 stdout"); 131 /* Cannot be 1 because pin allocated two descriptors. */ 132 close(pout[1]); 133 134 /* Stderr is left as it is so that error messages get 135 printed on the user's terminal. */ 136 argv[0] = _PATH_BSHELL; 137 argv[1] = "-c"; 138 argv[2] = command_string; 139 argv[3] = NULL; 140 141 /* Execute the proxy command. Note that we gave up any 142 extra privileges above. */ 143 execv(argv[0], argv); 144 perror(argv[0]); 145 exit(1); 146 } 147 /* Parent. */ 148 if (pid < 0) 149 fatal("fork failed: %.100s", strerror(errno)); 150 else 151 proxy_command_pid = pid; /* save pid to clean up later */ 152 153 /* Close child side of the descriptors. */ 154 close(pin[0]); 155 close(pout[1]); 156 157 /* Free the command name. */ 158 buffer_free(&command); 159 160 /* Set the connection file descriptors. */ 161 packet_set_connection(pout[0], pin[1]); 162 163 /* Indicate OK return */ 164 return 0; 165 } 166 167 /* 168 * Creates a (possibly privileged) socket for use as the ssh connection. 169 */ 170 static int 171 ssh_create_socket(int privileged, struct addrinfo *ai) 172 { 173 int sock, gaierr; 174 struct addrinfo hints, *res; 175 176 /* 177 * If we are running as root and want to connect to a privileged 178 * port, bind our own socket to a privileged port. 179 */ 180 if (privileged) { 181 int p = IPPORT_RESERVED - 1; 182 PRIV_START; 183 sock = rresvport_af(&p, ai->ai_family); 184 PRIV_END; 185 if (sock < 0) 186 error("rresvport: af=%d %.100s", ai->ai_family, 187 strerror(errno)); 188 else 189 debug("Allocated local port %d.", p); 190 return sock; 191 } 192 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 193 if (sock < 0) 194 error("socket: %.100s", strerror(errno)); 195 196 /* Bind the socket to an alternative local IP address */ 197 if (options.bind_address == NULL) 198 return sock; 199 200 memset(&hints, 0, sizeof(hints)); 201 hints.ai_family = ai->ai_family; 202 hints.ai_socktype = ai->ai_socktype; 203 hints.ai_protocol = ai->ai_protocol; 204 hints.ai_flags = AI_PASSIVE; 205 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); 206 if (gaierr) { 207 error("getaddrinfo: %s: %s", options.bind_address, 208 gai_strerror(gaierr)); 209 close(sock); 210 return -1; 211 } 212 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 213 error("bind: %s: %s", options.bind_address, strerror(errno)); 214 close(sock); 215 freeaddrinfo(res); 216 return -1; 217 } 218 freeaddrinfo(res); 219 return sock; 220 } 221 222 static int 223 timeout_connect(int sockfd, const struct sockaddr *serv_addr, 224 socklen_t addrlen, int timeout) 225 { 226 fd_set *fdset; 227 struct timeval tv; 228 socklen_t optlen; 229 int fdsetsz, optval, rc, result = -1; 230 231 if (timeout <= 0) 232 return (connect(sockfd, serv_addr, addrlen)); 233 234 set_nonblock(sockfd); 235 rc = connect(sockfd, serv_addr, addrlen); 236 if (rc == 0) { 237 unset_nonblock(sockfd); 238 return (0); 239 } 240 if (errno != EINPROGRESS) 241 return (-1); 242 243 fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); 244 fdset = (fd_set *)xmalloc(fdsetsz); 245 246 memset(fdset, 0, fdsetsz); 247 FD_SET(sockfd, fdset); 248 tv.tv_sec = timeout; 249 tv.tv_usec = 0; 250 251 for(;;) { 252 rc = select(sockfd + 1, NULL, fdset, NULL, &tv); 253 if (rc != -1 || errno != EINTR) 254 break; 255 } 256 257 switch(rc) { 258 case 0: 259 /* Timed out */ 260 errno = ETIMEDOUT; 261 break; 262 case -1: 263 /* Select error */ 264 debug("select: %s", strerror(errno)); 265 break; 266 case 1: 267 /* Completed or failed */ 268 optval = 0; 269 optlen = sizeof(optval); 270 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, 271 &optlen) == -1) { 272 debug("getsockopt: %s", strerror(errno)); 273 break; 274 } 275 if (optval != 0) { 276 errno = optval; 277 break; 278 } 279 result = 0; 280 unset_nonblock(sockfd); 281 break; 282 default: 283 /* Should not occur */ 284 fatal("Bogus return (%d) from select()", rc); 285 } 286 287 xfree(fdset); 288 return (result); 289 } 290 291 /* 292 * Opens a TCP/IP connection to the remote server on the given host. 293 * The address of the remote host will be returned in hostaddr. 294 * If port is 0, the default port will be used. If needpriv is true, 295 * a privileged port will be allocated to make the connection. 296 * This requires super-user privileges if needpriv is true. 297 * Connection_attempts specifies the maximum number of tries (one per 298 * second). If proxy_command is non-NULL, it specifies the command (with %h 299 * and %p substituted for host and port, respectively) to use to contact 300 * the daemon. 301 * Return values: 302 * 0 for OK 303 * ECONNREFUSED if we got a "Connection Refused" by the peer on any address 304 * ECONNABORTED if we failed without a "Connection refused" 305 * Suitable error messages for the connection failure will already have been 306 * printed. 307 */ 308 int 309 ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 310 u_short port, int family, int connection_attempts, 311 int needpriv, const char *proxy_command) 312 { 313 int gaierr; 314 int on = 1; 315 int sock = -1, attempt; 316 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 317 struct addrinfo hints, *ai, *aitop; 318 struct servent *sp; 319 /* 320 * Did we get only other errors than "Connection refused" (which 321 * should block fallback to rsh and similar), or did we get at least 322 * one "Connection refused"? 323 */ 324 int full_failure = 1; 325 326 debug2("ssh_connect: needpriv %d", needpriv); 327 328 /* Get default port if port has not been set. */ 329 if (port == 0) { 330 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 331 if (sp) 332 port = ntohs(sp->s_port); 333 else 334 port = SSH_DEFAULT_PORT; 335 } 336 /* If a proxy command is given, connect using it. */ 337 if (proxy_command != NULL) 338 return ssh_proxy_connect(host, port, proxy_command); 339 340 /* No proxy command. */ 341 342 memset(&hints, 0, sizeof(hints)); 343 hints.ai_family = family; 344 hints.ai_socktype = SOCK_STREAM; 345 snprintf(strport, sizeof strport, "%u", port); 346 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 347 fatal("%s: %.100s: %s", __progname, host, 348 gai_strerror(gaierr)); 349 350 /* 351 * Try to connect several times. On some machines, the first time 352 * will sometimes fail. In general socket code appears to behave 353 * quite magically on many machines. 354 */ 355 for (attempt = 0; ;) { 356 if (attempt > 0) 357 debug("Trying again..."); 358 359 /* Loop through addresses for this host, and try each one in 360 sequence until the connection succeeds. */ 361 for (ai = aitop; ai; ai = ai->ai_next) { 362 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 363 continue; 364 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 365 ntop, sizeof(ntop), strport, sizeof(strport), 366 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 367 error("ssh_connect: getnameinfo failed"); 368 continue; 369 } 370 debug("Connecting to %.200s [%.100s] port %s.", 371 host, ntop, strport); 372 373 /* Create a socket for connecting. */ 374 sock = ssh_create_socket(needpriv, ai); 375 if (sock < 0) 376 /* Any error is already output */ 377 continue; 378 379 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 380 options.connection_timeout) >= 0) { 381 /* Successful connection. */ 382 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 383 break; 384 } else { 385 if (errno == ECONNREFUSED) 386 full_failure = 0; 387 debug("connect to address %s port %s: %s", 388 ntop, strport, strerror(errno)); 389 /* 390 * Close the failed socket; there appear to 391 * be some problems when reusing a socket for 392 * which connect() has already returned an 393 * error. 394 */ 395 close(sock); 396 } 397 } 398 if (ai) 399 break; /* Successful connection. */ 400 401 attempt++; 402 if (attempt >= connection_attempts) 403 break; 404 /* Sleep a moment before retrying. */ 405 sleep(1); 406 } 407 408 freeaddrinfo(aitop); 409 410 /* Return failure if we didn't get a successful connection. */ 411 if (attempt >= connection_attempts) { 412 logit("ssh: connect to host %s port %s: %s", 413 host, strport, strerror(errno)); 414 return full_failure ? ECONNABORTED : ECONNREFUSED; 415 } 416 417 debug("Connection established."); 418 419 /* Set SO_KEEPALIVE if requested. */ 420 if (options.tcp_keep_alive && 421 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 422 sizeof(on)) < 0) 423 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 424 425 /* Set the connection. */ 426 packet_set_connection(sock, sock); 427 428 return 0; 429 } 430 431 /* 432 * Waits for the server identification string, and sends our own 433 * identification string. 434 */ 435 static void 436 ssh_exchange_identification(void) 437 { 438 char buf[256], remote_version[256]; /* must be same size! */ 439 int remote_major, remote_minor, i, mismatch; 440 int connection_in = packet_get_connection_in(); 441 int connection_out = packet_get_connection_out(); 442 int minor1 = PROTOCOL_MINOR_1; 443 444 /* Read other side\'s version identification. */ 445 for (;;) { 446 for (i = 0; i < sizeof(buf) - 1; i++) { 447 int len = atomicio(read, connection_in, &buf[i], 1); 448 if (len < 0) 449 fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); 450 if (len != 1) 451 fatal("ssh_exchange_identification: Connection closed by remote host"); 452 if (buf[i] == '\r') { 453 buf[i] = '\n'; 454 buf[i + 1] = 0; 455 continue; /**XXX wait for \n */ 456 } 457 if (buf[i] == '\n') { 458 buf[i + 1] = 0; 459 break; 460 } 461 } 462 buf[sizeof(buf) - 1] = 0; 463 if (strncmp(buf, "SSH-", 4) == 0) 464 break; 465 debug("ssh_exchange_identification: %s", buf); 466 } 467 server_version_string = xstrdup(buf); 468 469 /* 470 * Check that the versions match. In future this might accept 471 * several versions and set appropriate flags to handle them. 472 */ 473 if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n", 474 &remote_major, &remote_minor, remote_version) != 3) 475 fatal("Bad remote protocol version identification: '%.100s'", buf); 476 debug("Remote protocol version %d.%d, remote software version %.100s", 477 remote_major, remote_minor, remote_version); 478 479 compat_datafellows(remote_version); 480 mismatch = 0; 481 482 switch (remote_major) { 483 case 1: 484 if (remote_minor == 99 && 485 (options.protocol & SSH_PROTO_2) && 486 !(options.protocol & SSH_PROTO_1_PREFERRED)) { 487 enable_compat20(); 488 break; 489 } 490 if (!(options.protocol & SSH_PROTO_1)) { 491 mismatch = 1; 492 break; 493 } 494 if (remote_minor < 3) { 495 fatal("Remote machine has too old SSH software version."); 496 } else if (remote_minor == 3 || remote_minor == 4) { 497 /* We speak 1.3, too. */ 498 enable_compat13(); 499 minor1 = 3; 500 if (options.forward_agent) { 501 logit("Agent forwarding disabled for protocol 1.3"); 502 options.forward_agent = 0; 503 } 504 } 505 break; 506 case 2: 507 if (options.protocol & SSH_PROTO_2) { 508 enable_compat20(); 509 break; 510 } 511 /* FALLTHROUGH */ 512 default: 513 mismatch = 1; 514 break; 515 } 516 if (mismatch) 517 fatal("Protocol major versions differ: %d vs. %d", 518 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 519 remote_major); 520 /* Send our own protocol version identification. */ 521 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 522 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 523 compat20 ? PROTOCOL_MINOR_2 : minor1, 524 SSH_VERSION); 525 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) 526 fatal("write: %.100s", strerror(errno)); 527 client_version_string = xstrdup(buf); 528 chop(client_version_string); 529 chop(server_version_string); 530 debug("Local version string %.100s", client_version_string); 531 } 532 533 /* defaults to 'no' */ 534 static int 535 confirm(const char *prompt) 536 { 537 const char *msg, *again = "Please type 'yes' or 'no': "; 538 char *p; 539 int ret = -1; 540 541 if (options.batch_mode) 542 return 0; 543 for (msg = prompt;;msg = again) { 544 p = read_passphrase(msg, RP_ECHO); 545 if (p == NULL || 546 (p[0] == '\0') || (p[0] == '\n') || 547 strncasecmp(p, "no", 2) == 0) 548 ret = 0; 549 if (p && strncasecmp(p, "yes", 3) == 0) 550 ret = 1; 551 if (p) 552 xfree(p); 553 if (ret != -1) 554 return ret; 555 } 556 } 557 558 /* 559 * check whether the supplied host key is valid, return -1 if the key 560 * is not valid. the user_hostfile will not be updated if 'readonly' is true. 561 */ 562 static int 563 check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, 564 int readonly, const char *user_hostfile, const char *system_hostfile) 565 { 566 Key *file_key; 567 const char *type = key_type(host_key); 568 char *ip = NULL; 569 char hostline[1000], *hostp, *fp; 570 HostStatus host_status; 571 HostStatus ip_status; 572 int local = 0, host_ip_differ = 0; 573 int salen; 574 char ntop[NI_MAXHOST]; 575 char msg[1024]; 576 int len, host_line, ip_line; 577 const char *host_file = NULL, *ip_file = NULL; 578 579 /* 580 * Force accepting of the host key for loopback/localhost. The 581 * problem is that if the home directory is NFS-mounted to multiple 582 * machines, localhost will refer to a different machine in each of 583 * them, and the user will get bogus HOST_CHANGED warnings. This 584 * essentially disables host authentication for localhost; however, 585 * this is probably not a real problem. 586 */ 587 /** hostaddr == 0! */ 588 switch (hostaddr->sa_family) { 589 case AF_INET: 590 local = (ntohl(((struct sockaddr_in *)hostaddr)-> 591 sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 592 salen = sizeof(struct sockaddr_in); 593 break; 594 case AF_INET6: 595 local = IN6_IS_ADDR_LOOPBACK( 596 &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 597 salen = sizeof(struct sockaddr_in6); 598 break; 599 default: 600 local = 0; 601 salen = sizeof(struct sockaddr_storage); 602 break; 603 } 604 if (options.no_host_authentication_for_localhost == 1 && local && 605 options.host_key_alias == NULL) { 606 debug("Forcing accepting of host key for " 607 "loopback/localhost."); 608 return 0; 609 } 610 611 /* 612 * We don't have the remote ip-address for connections 613 * using a proxy command 614 */ 615 if (options.proxy_command == NULL) { 616 if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop), 617 NULL, 0, NI_NUMERICHOST) != 0) 618 fatal("check_host_key: getnameinfo failed"); 619 ip = xstrdup(ntop); 620 } else { 621 ip = xstrdup("<no hostip for proxy command>"); 622 } 623 /* 624 * Turn off check_host_ip if the connection is to localhost, via proxy 625 * command or if we don't have a hostname to compare with 626 */ 627 if (options.check_host_ip && 628 (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) 629 options.check_host_ip = 0; 630 631 /* 632 * Allow the user to record the key under a different name. This is 633 * useful for ssh tunneling over forwarded connections or if you run 634 * multiple sshd's on different ports on the same machine. 635 */ 636 if (options.host_key_alias != NULL) { 637 host = options.host_key_alias; 638 debug("using hostkeyalias: %s", host); 639 } 640 641 /* 642 * Store the host key from the known host file in here so that we can 643 * compare it with the key for the IP address. 644 */ 645 file_key = key_new(host_key->type); 646 647 /* 648 * Check if the host key is present in the user\'s list of known 649 * hosts or in the systemwide list. 650 */ 651 host_file = user_hostfile; 652 host_status = check_host_in_hostfile(host_file, host, host_key, 653 file_key, &host_line); 654 if (host_status == HOST_NEW) { 655 host_file = system_hostfile; 656 host_status = check_host_in_hostfile(host_file, host, host_key, 657 file_key, &host_line); 658 } 659 /* 660 * Also perform check for the ip address, skip the check if we are 661 * localhost or the hostname was an ip address to begin with 662 */ 663 if (options.check_host_ip) { 664 Key *ip_key = key_new(host_key->type); 665 666 ip_file = user_hostfile; 667 ip_status = check_host_in_hostfile(ip_file, ip, host_key, 668 ip_key, &ip_line); 669 if (ip_status == HOST_NEW) { 670 ip_file = system_hostfile; 671 ip_status = check_host_in_hostfile(ip_file, ip, 672 host_key, ip_key, &ip_line); 673 } 674 if (host_status == HOST_CHANGED && 675 (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) 676 host_ip_differ = 1; 677 678 key_free(ip_key); 679 } else 680 ip_status = host_status; 681 682 key_free(file_key); 683 684 switch (host_status) { 685 case HOST_OK: 686 /* The host is known and the key matches. */ 687 debug("Host '%.200s' is known and matches the %s host key.", 688 host, type); 689 debug("Found key in %s:%d", host_file, host_line); 690 if (options.check_host_ip && ip_status == HOST_NEW) { 691 if (readonly) 692 logit("%s host key for IP address " 693 "'%.128s' not in list of known hosts.", 694 type, ip); 695 else if (!add_host_to_hostfile(user_hostfile, ip, 696 host_key)) 697 logit("Failed to add the %s host key for IP " 698 "address '%.128s' to the list of known " 699 "hosts (%.30s).", type, ip, user_hostfile); 700 else 701 logit("Warning: Permanently added the %s host " 702 "key for IP address '%.128s' to the list " 703 "of known hosts.", type, ip); 704 } 705 break; 706 case HOST_NEW: 707 if (readonly) 708 goto fail; 709 /* The host is new. */ 710 if (options.strict_host_key_checking == 1) { 711 /* 712 * User has requested strict host key checking. We 713 * will not add the host key automatically. The only 714 * alternative left is to abort. 715 */ 716 error("No %s host key is known for %.200s and you " 717 "have requested strict checking.", type, host); 718 goto fail; 719 } else if (options.strict_host_key_checking == 2) { 720 char msg1[1024], msg2[1024]; 721 722 if (show_other_keys(host, host_key)) 723 snprintf(msg1, sizeof(msg1), 724 "\nbut keys of different type are already" 725 " known for this host."); 726 else 727 snprintf(msg1, sizeof(msg1), "."); 728 /* The default */ 729 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 730 msg2[0] = '\0'; 731 if (options.verify_host_key_dns) { 732 if (matching_host_key_dns) 733 snprintf(msg2, sizeof(msg2), 734 "Matching host key fingerprint" 735 " found in DNS.\n"); 736 else 737 snprintf(msg2, sizeof(msg2), 738 "No matching host key fingerprint" 739 " found in DNS.\n"); 740 } 741 snprintf(msg, sizeof(msg), 742 "The authenticity of host '%.200s (%s)' can't be " 743 "established%s\n" 744 "%s key fingerprint is %s.\n%s" 745 "Are you sure you want to continue connecting " 746 "(yes/no)? ", 747 host, ip, msg1, type, fp, msg2); 748 xfree(fp); 749 if (!confirm(msg)) 750 goto fail; 751 } 752 if (options.check_host_ip && ip_status == HOST_NEW) { 753 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 754 hostp = hostline; 755 } else 756 hostp = host; 757 758 /* 759 * If not in strict mode, add the key automatically to the 760 * local known_hosts file. 761 */ 762 if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) 763 logit("Failed to add the host to the list of known " 764 "hosts (%.500s).", user_hostfile); 765 else 766 logit("Warning: Permanently added '%.200s' (%s) to the " 767 "list of known hosts.", hostp, type); 768 break; 769 case HOST_CHANGED: 770 if (options.check_host_ip && host_ip_differ) { 771 char *msg; 772 if (ip_status == HOST_NEW) 773 msg = "is unknown"; 774 else if (ip_status == HOST_OK) 775 msg = "is unchanged"; 776 else 777 msg = "has a different value"; 778 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 779 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 780 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 781 error("The %s host key for %s has changed,", type, host); 782 error("and the key for the according IP address %s", ip); 783 error("%s. This could either mean that", msg); 784 error("DNS SPOOFING is happening or the IP address for the host"); 785 error("and its host key have changed at the same time."); 786 if (ip_status != HOST_NEW) 787 error("Offending key for IP in %s:%d", ip_file, ip_line); 788 } 789 /* The host key has changed. */ 790 warn_changed_key(host_key); 791 error("Add correct host key in %.100s to get rid of this message.", 792 user_hostfile); 793 error("Offending key in %s:%d", host_file, host_line); 794 795 /* 796 * If strict host key checking is in use, the user will have 797 * to edit the key manually and we can only abort. 798 */ 799 if (options.strict_host_key_checking) { 800 error("%s host key for %.200s has changed and you have " 801 "requested strict checking.", type, host); 802 goto fail; 803 } 804 805 /* 806 * If strict host key checking has not been requested, allow 807 * the connection but without MITM-able authentication or 808 * agent forwarding. 809 */ 810 if (options.password_authentication) { 811 error("Password authentication is disabled to avoid " 812 "man-in-the-middle attacks."); 813 options.password_authentication = 0; 814 } 815 if (options.kbd_interactive_authentication) { 816 error("Keyboard-interactive authentication is disabled" 817 " to avoid man-in-the-middle attacks."); 818 options.kbd_interactive_authentication = 0; 819 options.challenge_response_authentication = 0; 820 } 821 if (options.challenge_response_authentication) { 822 error("Challenge/response authentication is disabled" 823 " to avoid man-in-the-middle attacks."); 824 options.challenge_response_authentication = 0; 825 } 826 if (options.forward_agent) { 827 error("Agent forwarding is disabled to avoid " 828 "man-in-the-middle attacks."); 829 options.forward_agent = 0; 830 } 831 if (options.forward_x11) { 832 error("X11 forwarding is disabled to avoid " 833 "man-in-the-middle attacks."); 834 options.forward_x11 = 0; 835 } 836 if (options.num_local_forwards > 0 || 837 options.num_remote_forwards > 0) { 838 error("Port forwarding is disabled to avoid " 839 "man-in-the-middle attacks."); 840 options.num_local_forwards = 841 options.num_remote_forwards = 0; 842 } 843 /* 844 * XXX Should permit the user to change to use the new id. 845 * This could be done by converting the host key to an 846 * identifying sentence, tell that the host identifies itself 847 * by that sentence, and ask the user if he/she whishes to 848 * accept the authentication. 849 */ 850 break; 851 case HOST_FOUND: 852 fatal("internal error"); 853 break; 854 } 855 856 if (options.check_host_ip && host_status != HOST_CHANGED && 857 ip_status == HOST_CHANGED) { 858 snprintf(msg, sizeof(msg), 859 "Warning: the %s host key for '%.200s' " 860 "differs from the key for the IP address '%.128s'" 861 "\nOffending key for IP in %s:%d", 862 type, host, ip, ip_file, ip_line); 863 if (host_status == HOST_OK) { 864 len = strlen(msg); 865 snprintf(msg + len, sizeof(msg) - len, 866 "\nMatching host key in %s:%d", 867 host_file, host_line); 868 } 869 if (options.strict_host_key_checking == 1) { 870 logit("%s", msg); 871 error("Exiting, you have requested strict checking."); 872 goto fail; 873 } else if (options.strict_host_key_checking == 2) { 874 strlcat(msg, "\nAre you sure you want " 875 "to continue connecting (yes/no)? ", sizeof(msg)); 876 if (!confirm(msg)) 877 goto fail; 878 } else { 879 logit("%s", msg); 880 } 881 } 882 883 xfree(ip); 884 return 0; 885 886 fail: 887 xfree(ip); 888 return -1; 889 } 890 891 /* returns 0 if key verifies or -1 if key does NOT verify */ 892 int 893 verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 894 { 895 struct stat st; 896 int flags = 0; 897 898 if (options.verify_host_key_dns && 899 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { 900 901 if (flags & DNS_VERIFY_FOUND) { 902 903 if (options.verify_host_key_dns == 1 && 904 flags & DNS_VERIFY_MATCH && 905 flags & DNS_VERIFY_SECURE) 906 return 0; 907 908 if (flags & DNS_VERIFY_MATCH) { 909 matching_host_key_dns = 1; 910 } else { 911 warn_changed_key(host_key); 912 error("Update the SSHFP RR in DNS with the new " 913 "host key to get rid of this message."); 914 } 915 } 916 } 917 918 /* return ok if the key can be found in an old keyfile */ 919 if (stat(options.system_hostfile2, &st) == 0 || 920 stat(options.user_hostfile2, &st) == 0) { 921 if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, 922 options.user_hostfile2, options.system_hostfile2) == 0) 923 return 0; 924 } 925 return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, 926 options.user_hostfile, options.system_hostfile); 927 } 928 929 /* 930 * Starts a dialog with the server, and authenticates the current user on the 931 * server. This does not need any extra privileges. The basic connection 932 * to the server must already have been established before this is called. 933 * If login fails, this function prints an error and never returns. 934 * This function does not require super-user privileges. 935 */ 936 void 937 ssh_login(Sensitive *sensitive, const char *orighost, 938 struct sockaddr *hostaddr, struct passwd *pw) 939 { 940 char *host, *cp; 941 char *server_user, *local_user; 942 943 local_user = xstrdup(pw->pw_name); 944 server_user = options.user ? options.user : local_user; 945 946 /* Convert the user-supplied hostname into all lowercase. */ 947 host = xstrdup(orighost); 948 for (cp = host; *cp; cp++) 949 if (isupper(*cp)) 950 *cp = tolower(*cp); 951 952 /* Exchange protocol version identification strings with the server. */ 953 ssh_exchange_identification(); 954 955 /* Put the connection into non-blocking mode. */ 956 packet_set_nonblocking(); 957 958 /* key exchange */ 959 /* authenticate user */ 960 if (compat20) { 961 ssh_kex2(host, hostaddr); 962 ssh_userauth2(local_user, server_user, host, sensitive); 963 } else { 964 ssh_kex(host, hostaddr); 965 ssh_userauth1(local_user, server_user, host, sensitive); 966 } 967 } 968 969 void 970 ssh_put_password(char *password) 971 { 972 int size; 973 char *padded; 974 975 if (datafellows & SSH_BUG_PASSWORDPAD) { 976 packet_put_cstring(password); 977 return; 978 } 979 size = roundup(strlen(password) + 1, 32); 980 padded = xmalloc(size); 981 memset(padded, 0, size); 982 strlcpy(padded, password, size); 983 packet_put_string(padded, size); 984 memset(padded, 0, size); 985 xfree(padded); 986 } 987 988 static int 989 show_key_from_file(const char *file, const char *host, int keytype) 990 { 991 Key *found; 992 char *fp; 993 int line, ret; 994 995 found = key_new(keytype); 996 if ((ret = lookup_key_in_hostfile_by_type(file, host, 997 keytype, found, &line))) { 998 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 999 logit("WARNING: %s key found for host %s\n" 1000 "in %s:%d\n" 1001 "%s key fingerprint %s.", 1002 key_type(found), host, file, line, 1003 key_type(found), fp); 1004 xfree(fp); 1005 } 1006 key_free(found); 1007 return (ret); 1008 } 1009 1010 /* print all known host keys for a given host, but skip keys of given type */ 1011 static int 1012 show_other_keys(const char *host, Key *key) 1013 { 1014 int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; 1015 int i, found = 0; 1016 1017 for (i = 0; type[i] != -1; i++) { 1018 if (type[i] == key->type) 1019 continue; 1020 if (type[i] != KEY_RSA1 && 1021 show_key_from_file(options.user_hostfile2, host, type[i])) { 1022 found = 1; 1023 continue; 1024 } 1025 if (type[i] != KEY_RSA1 && 1026 show_key_from_file(options.system_hostfile2, host, type[i])) { 1027 found = 1; 1028 continue; 1029 } 1030 if (show_key_from_file(options.user_hostfile, host, type[i])) { 1031 found = 1; 1032 continue; 1033 } 1034 if (show_key_from_file(options.system_hostfile, host, type[i])) { 1035 found = 1; 1036 continue; 1037 } 1038 debug2("no key of type %d for host %s", type[i], host); 1039 } 1040 return (found); 1041 } 1042 1043 static void 1044 warn_changed_key(Key *host_key) 1045 { 1046 char *fp; 1047 const char *type = key_type(host_key); 1048 1049 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 1050 1051 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1052 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 1053 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1054 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1055 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1056 error("It is also possible that the %s host key has just been changed.", type); 1057 error("The fingerprint for the %s key sent by the remote host is\n%s.", 1058 type, fp); 1059 error("Please contact your system administrator."); 1060 1061 xfree(fp); 1062 } 1063