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