sshconnect.c revision 147005
155992Swpaul/* 255992Swpaul * Author: Tatu Ylonen <ylo@cs.hut.fi> 355992Swpaul * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 455992Swpaul * All rights reserved 555992Swpaul * Code to connect to a remote host, and to perform the client side of the 655992Swpaul * login (authentication) dialog. 755992Swpaul * 855992Swpaul * As far as I am concerned, the code I have written for this software 955992Swpaul * can be used freely for any purpose. Any derived versions of this 1055992Swpaul * software must be clearly marked as such, and if the derived work is 1155992Swpaul * incompatible with the protocol description in the RFC file, it must be 1255992Swpaul * called by a name other than "ssh" or "Secure Shell". 1355992Swpaul */ 1455992Swpaul 1555992Swpaul#include "includes.h" 1655992SwpaulRCSID("$OpenBSD: sshconnect.c,v 1.162 2005/03/10 22:01:06 deraadt Exp $"); 1755992Swpaul 1855992Swpaul#include <openssl/bn.h> 1955992Swpaul 2055992Swpaul#include "ssh.h" 2155992Swpaul#include "xmalloc.h" 2255992Swpaul#include "rsa.h" 2355992Swpaul#include "buffer.h" 2455992Swpaul#include "packet.h" 2555992Swpaul#include "uidswap.h" 2655992Swpaul#include "compat.h" 2755992Swpaul#include "key.h" 2855992Swpaul#include "sshconnect.h" 2955992Swpaul#include "hostfile.h" 3055992Swpaul#include "log.h" 3155992Swpaul#include "readconf.h" 3255992Swpaul#include "atomicio.h" 3355992Swpaul#include "misc.h" 3455992Swpaul 3555992Swpaul#include "dns.h" 3655992Swpaul 3755992Swpaulchar *client_version_string = NULL; 3855992Swpaulchar *server_version_string = NULL; 3955992Swpaul 4055992Swpaulint matching_host_key_dns = 0; 4155992Swpaul 4255992Swpaul/* import */ 4355992Swpaulextern Options options; 4455992Swpaulextern char *__progname; 4555992Swpaulextern uid_t original_real_uid; 4655992Swpaulextern uid_t original_effective_uid; 4755992Swpaulextern pid_t proxy_command_pid; 4855992Swpaul 4955992Swpaul#ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ 5055992Swpaul#define INET6_ADDRSTRLEN 46 5155992Swpaul#endif 5255992Swpaul 5355992Swpaulstatic int show_other_keys(const char *, Key *); 5455992Swpaulstatic void warn_changed_key(Key *); 5555992Swpaul 5655992Swpaul/* 5755992Swpaul * Connect to the given ssh server using a proxy command. 5855992Swpaul */ 5955992Swpaulstatic int 6055992Swpaulssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 6155992Swpaul{ 6255992Swpaul Buffer command; 6355992Swpaul const char *cp; 6455992Swpaul char *command_string; 6555992Swpaul int pin[2], pout[2]; 6655992Swpaul pid_t pid; 6755992Swpaul char strport[NI_MAXSERV]; 6855992Swpaul 6955992Swpaul /* Convert the port number into a string. */ 7055992Swpaul snprintf(strport, sizeof strport, "%hu", port); 7155992Swpaul 7284811Sjhb /* 7367365Sjhb * Build the final command string in the buffer by making the 7455992Swpaul * appropriate substitutions to the given proxy command. 7555992Swpaul * 7655992Swpaul * Use "exec" to avoid "sh -c" processes on some platforms 7755992Swpaul * (e.g. Solaris) 7855992Swpaul */ 7955992Swpaul buffer_init(&command); 8077217Sphk buffer_append(&command, "exec ", 5); 8155992Swpaul 8255992Swpaul for (cp = proxy_command; *cp; cp++) { 8355992Swpaul if (cp[0] == '%' && cp[1] == '%') { 8455992Swpaul buffer_append(&command, "%", 1); 8555992Swpaul cp++; 8655992Swpaul continue; 8755992Swpaul } 8855992Swpaul if (cp[0] == '%' && cp[1] == 'h') { 8955992Swpaul buffer_append(&command, host, strlen(host)); 9055992Swpaul cp++; 9155992Swpaul continue; 9255992Swpaul } 9355992Swpaul if (cp[0] == '%' && cp[1] == 'p') { 9455992Swpaul buffer_append(&command, strport, strlen(strport)); 9555992Swpaul cp++; 9655992Swpaul continue; 9755992Swpaul } 9855992Swpaul buffer_append(&command, cp, 1); 9955992Swpaul } 10081221Sbrooks buffer_append(&command, "\0", 1); 10155992Swpaul 10255992Swpaul /* Get the final command string. */ 10355992Swpaul command_string = buffer_ptr(&command); 104108401Sambrisko 10555992Swpaul /* Create pipes for communicating with the proxy. */ 10655992Swpaul if (pipe(pin) < 0 || pipe(pout) < 0) 10755992Swpaul fatal("Could not create pipes to communicate with the proxy: %.100s", 10855992Swpaul strerror(errno)); 10981221Sbrooks 11055992Swpaul debug("Executing proxy command: %.500s", command_string); 11155992Swpaul 11255992Swpaul /* Fork and execute the proxy command. */ 11355992Swpaul if ((pid = fork()) == 0) { 11455992Swpaul char *argv[10]; 11555992Swpaul 11692739Salfred /* Child. Permanently give up superuser privileges. */ 11792739Salfred seteuid(original_real_uid); 11892739Salfred setuid(original_real_uid); 11955992Swpaul 12083270Sbrooks /* Redirect stdin and stdout. */ 12183270Sbrooks close(pin[1]); 12255992Swpaul if (pin[0] != 0) { 12355992Swpaul if (dup2(pin[0], 0) < 0) 12455992Swpaul perror("dup2 stdin"); 12555992Swpaul close(pin[0]); 12655992Swpaul } 12783270Sbrooks close(pout[0]); 12855992Swpaul if (dup2(pout[1], 1) < 0) 12956051Swpaul perror("dup2 stdout"); 13055992Swpaul /* Cannot be 1 because pin allocated two descriptors. */ 13155992Swpaul close(pout[1]); 13255992Swpaul 13355992Swpaul /* Stderr is left as it is so that error messages get 13455992Swpaul printed on the user's terminal. */ 13555992Swpaul argv[0] = _PATH_BSHELL; 136108401Sambrisko argv[1] = "-c"; 137108401Sambrisko argv[2] = command_string; 138108401Sambrisko argv[3] = NULL; 139108401Sambrisko 140108401Sambrisko /* Execute the proxy command. Note that we gave up any 141108401Sambrisko extra privileges above. */ 14255992Swpaul execv(argv[0], argv); 14355992Swpaul perror(argv[0]); 14455992Swpaul exit(1); 14583270Sbrooks } 14683270Sbrooks /* Parent. */ 14755992Swpaul if (pid < 0) 14855992Swpaul fatal("fork failed: %.100s", strerror(errno)); 14955992Swpaul else 15055992Swpaul proxy_command_pid = pid; /* save pid to clean up later */ 15155992Swpaul 15255992Swpaul /* Close child side of the descriptors. */ 15355992Swpaul close(pin[0]); 15455992Swpaul close(pout[1]); 15555992Swpaul 15655992Swpaul /* Free the command name. */ 15783270Sbrooks buffer_free(&command); 158108401Sambrisko 159108401Sambrisko /* Set the connection file descriptors. */ 160108401Sambrisko packet_set_connection(pout[0], pin[1]); 161108401Sambrisko 162108401Sambrisko /* Indicate OK return */ 163108401Sambrisko return 0; 164108401Sambrisko} 165108401Sambrisko 166108401Sambrisko/* 167108401Sambrisko * Creates a (possibly privileged) socket for use as the ssh connection. 168108401Sambrisko */ 169108401Sambriskostatic int 17055992Swpaulssh_create_socket(int privileged, struct addrinfo *ai) 171108401Sambrisko{ 172108401Sambrisko int sock, gaierr; 173108401Sambrisko struct addrinfo hints, *res; 174108401Sambrisko 175108401Sambrisko /* 176108401Sambrisko * If we are running as root and want to connect to a privileged 17755992Swpaul * port, bind our own socket to a privileged port. 17855992Swpaul */ 17955992Swpaul if (privileged) { 18055992Swpaul int p = IPPORT_RESERVED - 1; 18155992Swpaul PRIV_START; 18255992Swpaul sock = rresvport_af(&p, ai->ai_family); 18355992Swpaul PRIV_END; 18455992Swpaul if (sock < 0) 18555992Swpaul error("rresvport: af=%d %.100s", ai->ai_family, 18655992Swpaul strerror(errno)); 18755992Swpaul else 188108401Sambrisko debug("Allocated local port %d.", p); 189108401Sambrisko return sock; 190108401Sambrisko } 191108401Sambrisko sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 192108401Sambrisko if (sock < 0) 193108401Sambrisko error("socket: %.100s", strerror(errno)); 194108401Sambrisko 195108401Sambrisko /* Bind the socket to an alternative local IP address */ 196108401Sambrisko if (options.bind_address == NULL) 197108401Sambrisko return sock; 198108401Sambrisko 199108401Sambrisko memset(&hints, 0, sizeof(hints)); 200108401Sambrisko hints.ai_family = ai->ai_family; 201108401Sambrisko hints.ai_socktype = ai->ai_socktype; 202108401Sambrisko hints.ai_protocol = ai->ai_protocol; 203108401Sambrisko hints.ai_flags = AI_PASSIVE; 204108401Sambrisko gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); 205108401Sambrisko if (gaierr) { 206108401Sambrisko error("getaddrinfo: %s: %s", options.bind_address, 207108401Sambrisko gai_strerror(gaierr)); 208108401Sambrisko close(sock); 209108401Sambrisko return -1; 210108401Sambrisko } 211108401Sambrisko if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 212108401Sambrisko error("bind: %s: %s", options.bind_address, strerror(errno)); 213108401Sambrisko close(sock); 214108401Sambrisko freeaddrinfo(res); 215108401Sambrisko return -1; 216108401Sambrisko } 217108401Sambrisko freeaddrinfo(res); 218108401Sambrisko return sock; 219108401Sambrisko} 220108401Sambrisko 221108401Sambriskostatic int 222108401Sambriskotimeout_connect(int sockfd, const struct sockaddr *serv_addr, 223108401Sambrisko socklen_t addrlen, int timeout) 224108401Sambrisko{ 225108401Sambrisko fd_set *fdset; 226108401Sambrisko struct timeval tv; 227108401Sambrisko socklen_t optlen; 22855992Swpaul int fdsetsz, optval, rc, result = -1; 22955992Swpaul 23055992Swpaul if (timeout <= 0) 23155992Swpaul return (connect(sockfd, serv_addr, addrlen)); 23255992Swpaul 23383270Sbrooks set_nonblock(sockfd); 23455992Swpaul rc = connect(sockfd, serv_addr, addrlen); 23555992Swpaul if (rc == 0) { 23655992Swpaul unset_nonblock(sockfd); 23755992Swpaul return (0); 23855992Swpaul } 23955992Swpaul if (errno != EINPROGRESS) 24067096Swpaul return (-1); 24155992Swpaul 24255992Swpaul fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); 24355992Swpaul fdset = (fd_set *)xmalloc(fdsetsz); 244108401Sambrisko 245108401Sambrisko memset(fdset, 0, fdsetsz); 24655992Swpaul FD_SET(sockfd, fdset); 24755992Swpaul tv.tv_sec = timeout; 24855992Swpaul tv.tv_usec = 0; 24983270Sbrooks 25055992Swpaul for (;;) { 25155992Swpaul rc = select(sockfd + 1, NULL, fdset, NULL, &tv); 25255992Swpaul if (rc != -1 || errno != EINTR) 25355992Swpaul break; 25455992Swpaul } 25555992Swpaul 25677217Sphk switch (rc) { 257106937Ssam case 0: 25855992Swpaul /* Timed out */ 25955992Swpaul errno = ETIMEDOUT; 26055992Swpaul break; 26155992Swpaul case -1: 26255992Swpaul /* Select error */ 26355992Swpaul debug("select: %s", strerror(errno)); 26455992Swpaul break; 26555992Swpaul case 1: 26655992Swpaul /* Completed or failed */ 26755992Swpaul optval = 0; 26855992Swpaul optlen = sizeof(optval); 26955992Swpaul if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, 27055992Swpaul &optlen) == -1) { 27155992Swpaul debug("getsockopt: %s", strerror(errno)); 27255992Swpaul break; 27355992Swpaul } 27455992Swpaul if (optval != 0) { 27555992Swpaul errno = optval; 27655992Swpaul break; 27755992Swpaul } 27855992Swpaul result = 0; 27955992Swpaul unset_nonblock(sockfd); 28055992Swpaul break; 28155992Swpaul default: 282 /* Should not occur */ 283 fatal("Bogus return (%d) from select()", rc); 284 } 285 286 xfree(fdset); 287 return (result); 288} 289 290/* 291 * Opens a TCP/IP connection to the remote server on the given host. 292 * The address of the remote host will be returned in hostaddr. 293 * If port is 0, the default port will be used. If needpriv is true, 294 * a privileged port will be allocated to make the connection. 295 * This requires super-user privileges if needpriv is true. 296 * Connection_attempts specifies the maximum number of tries (one per 297 * second). If proxy_command is non-NULL, it specifies the command (with %h 298 * and %p substituted for host and port, respectively) to use to contact 299 * the daemon. 300 */ 301int 302ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 303 u_short port, int family, int connection_attempts, 304 int needpriv, const char *proxy_command) 305{ 306 int gaierr; 307 int on = 1; 308 int sock = -1, attempt; 309 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 310 struct addrinfo hints, *ai, *aitop; 311 struct servent *sp; 312 313 debug2("ssh_connect: needpriv %d", needpriv); 314 315 /* Get default port if port has not been set. */ 316 if (port == 0) { 317 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 318 if (sp) 319 port = ntohs(sp->s_port); 320 else 321 port = SSH_DEFAULT_PORT; 322 } 323 /* If a proxy command is given, connect using it. */ 324 if (proxy_command != NULL) 325 return ssh_proxy_connect(host, port, proxy_command); 326 327 /* No proxy command. */ 328 329 memset(&hints, 0, sizeof(hints)); 330 hints.ai_family = family; 331 hints.ai_socktype = SOCK_STREAM; 332 snprintf(strport, sizeof strport, "%u", port); 333 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 334 fatal("%s: %.100s: %s", __progname, host, 335 gai_strerror(gaierr)); 336 337 /* 338 * Try to connect several times. On some machines, the first time 339 * will sometimes fail. In general socket code appears to behave 340 * quite magically on many machines. 341 */ 342 for (attempt = 0; ;) { 343 if (attempt > 0) 344 debug("Trying again..."); 345 346 /* Loop through addresses for this host, and try each one in 347 sequence until the connection succeeds. */ 348 for (ai = aitop; ai; ai = ai->ai_next) { 349 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 350 continue; 351 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 352 ntop, sizeof(ntop), strport, sizeof(strport), 353 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 354 error("ssh_connect: getnameinfo failed"); 355 continue; 356 } 357 debug("Connecting to %.200s [%.100s] port %s.", 358 host, ntop, strport); 359 360 /* Create a socket for connecting. */ 361 sock = ssh_create_socket(needpriv, ai); 362 if (sock < 0) 363 /* Any error is already output */ 364 continue; 365 366 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 367 options.connection_timeout) >= 0) { 368 /* Successful connection. */ 369 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 370 break; 371 } else { 372 debug("connect to address %s port %s: %s", 373 ntop, strport, strerror(errno)); 374 /* 375 * Close the failed socket; there appear to 376 * be some problems when reusing a socket for 377 * which connect() has already returned an 378 * error. 379 */ 380 close(sock); 381 } 382 } 383 if (ai) 384 break; /* Successful connection. */ 385 386 attempt++; 387 if (attempt >= connection_attempts) 388 break; 389 /* Sleep a moment before retrying. */ 390 sleep(1); 391 } 392 393 freeaddrinfo(aitop); 394 395 /* Return failure if we didn't get a successful connection. */ 396 if (attempt >= connection_attempts) { 397 error("ssh: connect to host %s port %s: %s", 398 host, strport, strerror(errno)); 399 return (-1); 400 } 401 402 debug("Connection established."); 403 404 /* Set SO_KEEPALIVE if requested. */ 405 if (options.tcp_keep_alive && 406 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 407 sizeof(on)) < 0) 408 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 409 410 /* Set the connection. */ 411 packet_set_connection(sock, sock); 412 413 return 0; 414} 415 416/* 417 * Waits for the server identification string, and sends our own 418 * identification string. 419 */ 420static void 421ssh_exchange_identification(void) 422{ 423 char buf[256], remote_version[256]; /* must be same size! */ 424 int remote_major, remote_minor, i, mismatch; 425 int connection_in = packet_get_connection_in(); 426 int connection_out = packet_get_connection_out(); 427 int minor1 = PROTOCOL_MINOR_1; 428 429 /* Read other side\'s version identification. */ 430 for (;;) { 431 for (i = 0; i < sizeof(buf) - 1; i++) { 432 int len = atomicio(read, connection_in, &buf[i], 1); 433 if (len < 0) 434 fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); 435 if (len != 1) 436 fatal("ssh_exchange_identification: Connection closed by remote host"); 437 if (buf[i] == '\r') { 438 buf[i] = '\n'; 439 buf[i + 1] = 0; 440 continue; /**XXX wait for \n */ 441 } 442 if (buf[i] == '\n') { 443 buf[i + 1] = 0; 444 break; 445 } 446 } 447 buf[sizeof(buf) - 1] = 0; 448 if (strncmp(buf, "SSH-", 4) == 0) 449 break; 450 debug("ssh_exchange_identification: %s", buf); 451 } 452 server_version_string = xstrdup(buf); 453 454 /* 455 * Check that the versions match. In future this might accept 456 * several versions and set appropriate flags to handle them. 457 */ 458 if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n", 459 &remote_major, &remote_minor, remote_version) != 3) 460 fatal("Bad remote protocol version identification: '%.100s'", buf); 461 debug("Remote protocol version %d.%d, remote software version %.100s", 462 remote_major, remote_minor, remote_version); 463 464 compat_datafellows(remote_version); 465 mismatch = 0; 466 467 switch (remote_major) { 468 case 1: 469 if (remote_minor == 99 && 470 (options.protocol & SSH_PROTO_2) && 471 !(options.protocol & SSH_PROTO_1_PREFERRED)) { 472 enable_compat20(); 473 break; 474 } 475 if (!(options.protocol & SSH_PROTO_1)) { 476 mismatch = 1; 477 break; 478 } 479 if (remote_minor < 3) { 480 fatal("Remote machine has too old SSH software version."); 481 } else if (remote_minor == 3 || remote_minor == 4) { 482 /* We speak 1.3, too. */ 483 enable_compat13(); 484 minor1 = 3; 485 if (options.forward_agent) { 486 logit("Agent forwarding disabled for protocol 1.3"); 487 options.forward_agent = 0; 488 } 489 } 490 break; 491 case 2: 492 if (options.protocol & SSH_PROTO_2) { 493 enable_compat20(); 494 break; 495 } 496 /* FALLTHROUGH */ 497 default: 498 mismatch = 1; 499 break; 500 } 501 if (mismatch) 502 fatal("Protocol major versions differ: %d vs. %d", 503 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 504 remote_major); 505 /* Send our own protocol version identification. */ 506 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 507 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 508 compat20 ? PROTOCOL_MINOR_2 : minor1, 509 SSH_VERSION); 510 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) 511 fatal("write: %.100s", strerror(errno)); 512 client_version_string = xstrdup(buf); 513 chop(client_version_string); 514 chop(server_version_string); 515 debug("Local version string %.100s", client_version_string); 516} 517 518/* defaults to 'no' */ 519static int 520confirm(const char *prompt) 521{ 522 const char *msg, *again = "Please type 'yes' or 'no': "; 523 char *p; 524 int ret = -1; 525 526 if (options.batch_mode) 527 return 0; 528 for (msg = prompt;;msg = again) { 529 p = read_passphrase(msg, RP_ECHO); 530 if (p == NULL || 531 (p[0] == '\0') || (p[0] == '\n') || 532 strncasecmp(p, "no", 2) == 0) 533 ret = 0; 534 if (p && strncasecmp(p, "yes", 3) == 0) 535 ret = 1; 536 if (p) 537 xfree(p); 538 if (ret != -1) 539 return ret; 540 } 541} 542 543/* 544 * check whether the supplied host key is valid, return -1 if the key 545 * is not valid. the user_hostfile will not be updated if 'readonly' is true. 546 */ 547static int 548check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, 549 int readonly, const char *user_hostfile, const char *system_hostfile) 550{ 551 Key *file_key; 552 const char *type = key_type(host_key); 553 char *ip = NULL; 554 char hostline[1000], *hostp, *fp; 555 HostStatus host_status; 556 HostStatus ip_status; 557 int r, local = 0, host_ip_differ = 0; 558 int salen; 559 char ntop[NI_MAXHOST]; 560 char msg[1024]; 561 int len, host_line, ip_line; 562 const char *host_file = NULL, *ip_file = NULL; 563 564 /* 565 * Force accepting of the host key for loopback/localhost. The 566 * problem is that if the home directory is NFS-mounted to multiple 567 * machines, localhost will refer to a different machine in each of 568 * them, and the user will get bogus HOST_CHANGED warnings. This 569 * essentially disables host authentication for localhost; however, 570 * this is probably not a real problem. 571 */ 572 /** hostaddr == 0! */ 573 switch (hostaddr->sa_family) { 574 case AF_INET: 575 local = (ntohl(((struct sockaddr_in *)hostaddr)-> 576 sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 577 salen = sizeof(struct sockaddr_in); 578 break; 579 case AF_INET6: 580 local = IN6_IS_ADDR_LOOPBACK( 581 &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 582 salen = sizeof(struct sockaddr_in6); 583 break; 584 default: 585 local = 0; 586 salen = sizeof(struct sockaddr_storage); 587 break; 588 } 589 if (options.no_host_authentication_for_localhost == 1 && local && 590 options.host_key_alias == NULL) { 591 debug("Forcing accepting of host key for " 592 "loopback/localhost."); 593 return 0; 594 } 595 596 /* 597 * We don't have the remote ip-address for connections 598 * using a proxy command 599 */ 600 if (options.proxy_command == NULL) { 601 if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop), 602 NULL, 0, NI_NUMERICHOST) != 0) 603 fatal("check_host_key: getnameinfo failed"); 604 ip = xstrdup(ntop); 605 } else { 606 ip = xstrdup("<no hostip for proxy command>"); 607 } 608 /* 609 * Turn off check_host_ip if the connection is to localhost, via proxy 610 * command or if we don't have a hostname to compare with 611 */ 612 if (options.check_host_ip && 613 (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) 614 options.check_host_ip = 0; 615 616 /* 617 * Allow the user to record the key under a different name. This is 618 * useful for ssh tunneling over forwarded connections or if you run 619 * multiple sshd's on different ports on the same machine. 620 */ 621 if (options.host_key_alias != NULL) { 622 host = options.host_key_alias; 623 debug("using hostkeyalias: %s", host); 624 } 625 626 /* 627 * Store the host key from the known host file in here so that we can 628 * compare it with the key for the IP address. 629 */ 630 file_key = key_new(host_key->type); 631 632 /* 633 * Check if the host key is present in the user\'s list of known 634 * hosts or in the systemwide list. 635 */ 636 host_file = user_hostfile; 637 host_status = check_host_in_hostfile(host_file, host, host_key, 638 file_key, &host_line); 639 if (host_status == HOST_NEW) { 640 host_file = system_hostfile; 641 host_status = check_host_in_hostfile(host_file, host, host_key, 642 file_key, &host_line); 643 } 644 /* 645 * Also perform check for the ip address, skip the check if we are 646 * localhost or the hostname was an ip address to begin with 647 */ 648 if (options.check_host_ip) { 649 Key *ip_key = key_new(host_key->type); 650 651 ip_file = user_hostfile; 652 ip_status = check_host_in_hostfile(ip_file, ip, host_key, 653 ip_key, &ip_line); 654 if (ip_status == HOST_NEW) { 655 ip_file = system_hostfile; 656 ip_status = check_host_in_hostfile(ip_file, ip, 657 host_key, ip_key, &ip_line); 658 } 659 if (host_status == HOST_CHANGED && 660 (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) 661 host_ip_differ = 1; 662 663 key_free(ip_key); 664 } else 665 ip_status = host_status; 666 667 key_free(file_key); 668 669 switch (host_status) { 670 case HOST_OK: 671 /* The host is known and the key matches. */ 672 debug("Host '%.200s' is known and matches the %s host key.", 673 host, type); 674 debug("Found key in %s:%d", host_file, host_line); 675 if (options.check_host_ip && ip_status == HOST_NEW) { 676 if (readonly) 677 logit("%s host key for IP address " 678 "'%.128s' not in list of known hosts.", 679 type, ip); 680 else if (!add_host_to_hostfile(user_hostfile, ip, 681 host_key, options.hash_known_hosts)) 682 logit("Failed to add the %s host key for IP " 683 "address '%.128s' to the list of known " 684 "hosts (%.30s).", type, ip, user_hostfile); 685 else 686 logit("Warning: Permanently added the %s host " 687 "key for IP address '%.128s' to the list " 688 "of known hosts.", type, ip); 689 } 690 break; 691 case HOST_NEW: 692 if (readonly) 693 goto fail; 694 /* The host is new. */ 695 if (options.strict_host_key_checking == 1) { 696 /* 697 * User has requested strict host key checking. We 698 * will not add the host key automatically. The only 699 * alternative left is to abort. 700 */ 701 error("No %s host key is known for %.200s and you " 702 "have requested strict checking.", type, host); 703 goto fail; 704 } else if (options.strict_host_key_checking == 2) { 705 char msg1[1024], msg2[1024]; 706 707 if (show_other_keys(host, host_key)) 708 snprintf(msg1, sizeof(msg1), 709 "\nbut keys of different type are already" 710 " known for this host."); 711 else 712 snprintf(msg1, sizeof(msg1), "."); 713 /* The default */ 714 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 715 msg2[0] = '\0'; 716 if (options.verify_host_key_dns) { 717 if (matching_host_key_dns) 718 snprintf(msg2, sizeof(msg2), 719 "Matching host key fingerprint" 720 " found in DNS.\n"); 721 else 722 snprintf(msg2, sizeof(msg2), 723 "No matching host key fingerprint" 724 " found in DNS.\n"); 725 } 726 snprintf(msg, sizeof(msg), 727 "The authenticity of host '%.200s (%s)' can't be " 728 "established%s\n" 729 "%s key fingerprint is %s.\n%s" 730 "Are you sure you want to continue connecting " 731 "(yes/no)? ", 732 host, ip, msg1, type, fp, msg2); 733 xfree(fp); 734 if (!confirm(msg)) 735 goto fail; 736 } 737 /* 738 * If not in strict mode, add the key automatically to the 739 * local known_hosts file. 740 */ 741 if (options.check_host_ip && ip_status == HOST_NEW) { 742 snprintf(hostline, sizeof(hostline), "%s,%s", 743 host, ip); 744 hostp = hostline; 745 if (options.hash_known_hosts) { 746 /* Add hash of host and IP separately */ 747 r = add_host_to_hostfile(user_hostfile, host, 748 host_key, options.hash_known_hosts) && 749 add_host_to_hostfile(user_hostfile, ip, 750 host_key, options.hash_known_hosts); 751 } else { 752 /* Add unhashed "host,ip" */ 753 r = add_host_to_hostfile(user_hostfile, 754 hostline, host_key, 755 options.hash_known_hosts); 756 } 757 } else { 758 r = add_host_to_hostfile(user_hostfile, host, host_key, 759 options.hash_known_hosts); 760 hostp = host; 761 } 762 763 if (!r) 764 logit("Failed to add the host to the list of known " 765 "hosts (%.500s).", user_hostfile); 766 else 767 logit("Warning: Permanently added '%.200s' (%s) to the " 768 "list of known hosts.", hostp, type); 769 break; 770 case HOST_CHANGED: 771 if (options.check_host_ip && host_ip_differ) { 772 char *key_msg; 773 if (ip_status == HOST_NEW) 774 key_msg = "is unknown"; 775 else if (ip_status == HOST_OK) 776 key_msg = "is unchanged"; 777 else 778 key_msg = "has a different value"; 779 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 780 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 781 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 782 error("The %s host key for %s has changed,", type, host); 783 error("and the key for the according IP address %s", ip); 784 error("%s. This could either mean that", key_msg); 785 error("DNS SPOOFING is happening or the IP address for the host"); 786 error("and its host key have changed at the same time."); 787 if (ip_status != HOST_NEW) 788 error("Offending key for IP in %s:%d", ip_file, ip_line); 789 } 790 /* The host key has changed. */ 791 warn_changed_key(host_key); 792 error("Add correct host key in %.100s to get rid of this message.", 793 user_hostfile); 794 error("Offending key in %s:%d", host_file, host_line); 795 796 /* 797 * If strict host key checking is in use, the user will have 798 * to edit the key manually and we can only abort. 799 */ 800 if (options.strict_host_key_checking) { 801 error("%s host key for %.200s has changed and you have " 802 "requested strict checking.", type, host); 803 goto fail; 804 } 805 806 /* 807 * If strict host key checking has not been requested, allow 808 * the connection but without MITM-able authentication or 809 * agent forwarding. 810 */ 811 if (options.password_authentication) { 812 error("Password authentication is disabled to avoid " 813 "man-in-the-middle attacks."); 814 options.password_authentication = 0; 815 } 816 if (options.kbd_interactive_authentication) { 817 error("Keyboard-interactive authentication is disabled" 818 " to avoid man-in-the-middle attacks."); 819 options.kbd_interactive_authentication = 0; 820 options.challenge_response_authentication = 0; 821 } 822 if (options.challenge_response_authentication) { 823 error("Challenge/response authentication is disabled" 824 " to avoid man-in-the-middle attacks."); 825 options.challenge_response_authentication = 0; 826 } 827 if (options.forward_agent) { 828 error("Agent forwarding is disabled to avoid " 829 "man-in-the-middle attacks."); 830 options.forward_agent = 0; 831 } 832 if (options.forward_x11) { 833 error("X11 forwarding is disabled to avoid " 834 "man-in-the-middle attacks."); 835 options.forward_x11 = 0; 836 } 837 if (options.num_local_forwards > 0 || 838 options.num_remote_forwards > 0) { 839 error("Port forwarding is disabled to avoid " 840 "man-in-the-middle attacks."); 841 options.num_local_forwards = 842 options.num_remote_forwards = 0; 843 } 844 /* 845 * XXX Should permit the user to change to use the new id. 846 * This could be done by converting the host key to an 847 * identifying sentence, tell that the host identifies itself 848 * by that sentence, and ask the user if he/she whishes to 849 * accept the authentication. 850 */ 851 break; 852 case HOST_FOUND: 853 fatal("internal error"); 854 break; 855 } 856 857 if (options.check_host_ip && host_status != HOST_CHANGED && 858 ip_status == HOST_CHANGED) { 859 snprintf(msg, sizeof(msg), 860 "Warning: the %s host key for '%.200s' " 861 "differs from the key for the IP address '%.128s'" 862 "\nOffending key for IP in %s:%d", 863 type, host, ip, ip_file, ip_line); 864 if (host_status == HOST_OK) { 865 len = strlen(msg); 866 snprintf(msg + len, sizeof(msg) - len, 867 "\nMatching host key in %s:%d", 868 host_file, host_line); 869 } 870 if (options.strict_host_key_checking == 1) { 871 logit("%s", msg); 872 error("Exiting, you have requested strict checking."); 873 goto fail; 874 } else if (options.strict_host_key_checking == 2) { 875 strlcat(msg, "\nAre you sure you want " 876 "to continue connecting (yes/no)? ", sizeof(msg)); 877 if (!confirm(msg)) 878 goto fail; 879 } else { 880 logit("%s", msg); 881 } 882 } 883 884 xfree(ip); 885 return 0; 886 887fail: 888 xfree(ip); 889 return -1; 890} 891 892/* returns 0 if key verifies or -1 if key does NOT verify */ 893int 894verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 895{ 896 struct stat st; 897 int flags = 0; 898 899 if (options.verify_host_key_dns && 900 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { 901 902 if (flags & DNS_VERIFY_FOUND) { 903 904 if (options.verify_host_key_dns == 1 && 905 flags & DNS_VERIFY_MATCH && 906 flags & DNS_VERIFY_SECURE) 907 return 0; 908 909 if (flags & DNS_VERIFY_MATCH) { 910 matching_host_key_dns = 1; 911 } else { 912 warn_changed_key(host_key); 913 error("Update the SSHFP RR in DNS with the new " 914 "host key to get rid of this message."); 915 } 916 } 917 } 918 919 /* return ok if the key can be found in an old keyfile */ 920 if (stat(options.system_hostfile2, &st) == 0 || 921 stat(options.user_hostfile2, &st) == 0) { 922 if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, 923 options.user_hostfile2, options.system_hostfile2) == 0) 924 return 0; 925 } 926 return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, 927 options.user_hostfile, options.system_hostfile); 928} 929 930/* 931 * Starts a dialog with the server, and authenticates the current user on the 932 * server. This does not need any extra privileges. The basic connection 933 * to the server must already have been established before this is called. 934 * If login fails, this function prints an error and never returns. 935 * This function does not require super-user privileges. 936 */ 937void 938ssh_login(Sensitive *sensitive, const char *orighost, 939 struct sockaddr *hostaddr, struct passwd *pw) 940{ 941 char *host, *cp; 942 char *server_user, *local_user; 943 944 local_user = xstrdup(pw->pw_name); 945 server_user = options.user ? options.user : local_user; 946 947 /* Convert the user-supplied hostname into all lowercase. */ 948 host = xstrdup(orighost); 949 for (cp = host; *cp; cp++) 950 if (isupper(*cp)) 951 *cp = tolower(*cp); 952 953 /* Exchange protocol version identification strings with the server. */ 954 ssh_exchange_identification(); 955 956 /* Put the connection into non-blocking mode. */ 957 packet_set_nonblocking(); 958 959 /* key exchange */ 960 /* authenticate user */ 961 if (compat20) { 962 ssh_kex2(host, hostaddr); 963 ssh_userauth2(local_user, server_user, host, sensitive); 964 } else { 965 ssh_kex(host, hostaddr); 966 ssh_userauth1(local_user, server_user, host, sensitive); 967 } 968} 969 970void 971ssh_put_password(char *password) 972{ 973 int size; 974 char *padded; 975 976 if (datafellows & SSH_BUG_PASSWORDPAD) { 977 packet_put_cstring(password); 978 return; 979 } 980 size = roundup(strlen(password) + 1, 32); 981 padded = xmalloc(size); 982 memset(padded, 0, size); 983 strlcpy(padded, password, size); 984 packet_put_string(padded, size); 985 memset(padded, 0, size); 986 xfree(padded); 987} 988 989static int 990show_key_from_file(const char *file, const char *host, int keytype) 991{ 992 Key *found; 993 char *fp; 994 int line, ret; 995 996 found = key_new(keytype); 997 if ((ret = lookup_key_in_hostfile_by_type(file, host, 998 keytype, found, &line))) { 999 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 1000 logit("WARNING: %s key found for host %s\n" 1001 "in %s:%d\n" 1002 "%s key fingerprint %s.", 1003 key_type(found), host, file, line, 1004 key_type(found), fp); 1005 xfree(fp); 1006 } 1007 key_free(found); 1008 return (ret); 1009} 1010 1011/* print all known host keys for a given host, but skip keys of given type */ 1012static int 1013show_other_keys(const char *host, Key *key) 1014{ 1015 int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; 1016 int i, found = 0; 1017 1018 for (i = 0; type[i] != -1; i++) { 1019 if (type[i] == key->type) 1020 continue; 1021 if (type[i] != KEY_RSA1 && 1022 show_key_from_file(options.user_hostfile2, host, type[i])) { 1023 found = 1; 1024 continue; 1025 } 1026 if (type[i] != KEY_RSA1 && 1027 show_key_from_file(options.system_hostfile2, host, type[i])) { 1028 found = 1; 1029 continue; 1030 } 1031 if (show_key_from_file(options.user_hostfile, host, type[i])) { 1032 found = 1; 1033 continue; 1034 } 1035 if (show_key_from_file(options.system_hostfile, host, type[i])) { 1036 found = 1; 1037 continue; 1038 } 1039 debug2("no key of type %d for host %s", type[i], host); 1040 } 1041 return (found); 1042} 1043 1044static void 1045warn_changed_key(Key *host_key) 1046{ 1047 char *fp; 1048 const char *type = key_type(host_key); 1049 1050 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 1051 1052 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1053 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 1054 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1055 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1056 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1057 error("It is also possible that the %s host key has just been changed.", type); 1058 error("The fingerprint for the %s key sent by the remote host is\n%s.", 1059 type, fp); 1060 error("Please contact your system administrator."); 1061 1062 xfree(fp); 1063} 1064