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