summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c339
1 files changed, 138 insertions, 201 deletions
diff --git a/sshconnect.c b/sshconnect.c
index d9ed5910b..3280b310d 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.273 2017/03/10 03:22:40 dtucker Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.287 2017/09/14 04:32:21 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,6 +34,9 @@
34#include <paths.h> 34#include <paths.h>
35#endif 35#endif
36#include <pwd.h> 36#include <pwd.h>
37#ifdef HAVE_POLL_H
38#include <poll.h>
39#endif
37#include <signal.h> 40#include <signal.h>
38#include <stdarg.h> 41#include <stdarg.h>
39#include <stdio.h> 42#include <stdio.h>
@@ -45,7 +48,6 @@
45#include "key.h" 48#include "key.h"
46#include "hostfile.h" 49#include "hostfile.h"
47#include "ssh.h" 50#include "ssh.h"
48#include "rsa.h"
49#include "buffer.h" 51#include "buffer.h"
50#include "packet.h" 52#include "packet.h"
51#include "uidswap.h" 53#include "uidswap.h"
@@ -67,7 +69,7 @@
67 69
68char *client_version_string = NULL; 70char *client_version_string = NULL;
69char *server_version_string = NULL; 71char *server_version_string = NULL;
70Key *previous_host_key = NULL; 72struct sshkey *previous_host_key = NULL;
71 73
72static int matching_host_key_dns = 0; 74static int matching_host_key_dns = 0;
73 75
@@ -79,8 +81,8 @@ extern char *__progname;
79extern uid_t original_real_uid; 81extern uid_t original_real_uid;
80extern uid_t original_effective_uid; 82extern uid_t original_effective_uid;
81 83
82static int show_other_keys(struct hostkeys *, Key *); 84static int show_other_keys(struct hostkeys *, struct sshkey *);
83static void warn_changed_key(Key *); 85static void warn_changed_key(struct sshkey *);
84 86
85/* Expand a proxy command */ 87/* Expand a proxy command */
86static char * 88static char *
@@ -102,7 +104,7 @@ expand_proxy_command(const char *proxy_command, const char *user,
102 * a connected fd back to us. 104 * a connected fd back to us.
103 */ 105 */
104static int 106static int
105ssh_proxy_fdpass_connect(const char *host, u_short port, 107ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host, u_short port,
106 const char *proxy_command) 108 const char *proxy_command)
107{ 109{
108 char *command_string; 110 char *command_string;
@@ -173,7 +175,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
173 fatal("Couldn't wait for child: %s", strerror(errno)); 175 fatal("Couldn't wait for child: %s", strerror(errno));
174 176
175 /* Set the connection file descriptors. */ 177 /* Set the connection file descriptors. */
176 packet_set_connection(sock, sock); 178 if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
179 return -1; /* ssh_packet_set_connection logs error */
177 180
178 return 0; 181 return 0;
179} 182}
@@ -182,7 +185,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
182 * Connect to the given ssh server using a proxy command. 185 * Connect to the given ssh server using a proxy command.
183 */ 186 */
184static int 187static int
185ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 188ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
189 const char *proxy_command)
186{ 190{
187 char *command_string; 191 char *command_string;
188 int pin[2], pout[2]; 192 int pin[2], pout[2];
@@ -249,9 +253,9 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
249 free(command_string); 253 free(command_string);
250 254
251 /* Set the connection file descriptors. */ 255 /* Set the connection file descriptors. */
252 packet_set_connection(pout[0], pin[1]); 256 if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL)
257 return -1; /* ssh_packet_set_connection logs error */
253 258
254 /* Indicate OK return */
255 return 0; 259 return 0;
256} 260}
257 261
@@ -328,87 +332,71 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
328 return sock; 332 return sock;
329} 333}
330 334
335/*
336 * Wait up to *timeoutp milliseconds for fd to be readable. Updates
337 * *timeoutp with time remaining.
338 * Returns 0 if fd ready or -1 on timeout or error (see errno).
339 */
331static int 340static int
332timeout_connect(int sockfd, const struct sockaddr *serv_addr, 341waitrfd(int fd, int *timeoutp)
333 socklen_t addrlen, int *timeoutp)
334{ 342{
335 fd_set *fdset; 343 struct pollfd pfd;
336 struct timeval tv, t_start; 344 struct timeval t_start;
337 socklen_t optlen; 345 int oerrno, r;
338 int optval, rc, result = -1;
339 346
340 gettimeofday(&t_start, NULL); 347 gettimeofday(&t_start, NULL);
341 348 pfd.fd = fd;
342 if (*timeoutp <= 0) { 349 pfd.events = POLLIN;
343 result = connect(sockfd, serv_addr, addrlen); 350 for (; *timeoutp >= 0;) {
344 goto done; 351 r = poll(&pfd, 1, *timeoutp);
345 } 352 oerrno = errno;
346 353 ms_subtract_diff(&t_start, timeoutp);
347 set_nonblock(sockfd); 354 errno = oerrno;
348 rc = connect(sockfd, serv_addr, addrlen); 355 if (r > 0)
349 if (rc == 0) { 356 return 0;
350 unset_nonblock(sockfd); 357 else if (r == -1 && errno != EAGAIN)
351 result = 0; 358 return -1;
352 goto done; 359 else if (r == 0)
353 } 360 break;
354 if (errno != EINPROGRESS) {
355 result = -1;
356 goto done;
357 } 361 }
362 /* timeout */
363 errno = ETIMEDOUT;
364 return -1;
365}
358 366
359 fdset = xcalloc(howmany(sockfd + 1, NFDBITS), 367static int
360 sizeof(fd_mask)); 368timeout_connect(int sockfd, const struct sockaddr *serv_addr,
361 FD_SET(sockfd, fdset); 369 socklen_t addrlen, int *timeoutp)
362 ms_to_timeval(&tv, *timeoutp); 370{
371 int optval = 0;
372 socklen_t optlen = sizeof(optval);
363 373
364 for (;;) { 374 /* No timeout: just do a blocking connect() */
365 rc = select(sockfd + 1, NULL, fdset, NULL, &tv); 375 if (*timeoutp <= 0)
366 if (rc != -1 || errno != EINTR) 376 return connect(sockfd, serv_addr, addrlen);
367 break;
368 }
369 377
370 switch (rc) { 378 set_nonblock(sockfd);
371 case 0: 379 if (connect(sockfd, serv_addr, addrlen) == 0) {
372 /* Timed out */ 380 /* Succeeded already? */
373 errno = ETIMEDOUT;
374 break;
375 case -1:
376 /* Select error */
377 debug("select: %s", strerror(errno));
378 break;
379 case 1:
380 /* Completed or failed */
381 optval = 0;
382 optlen = sizeof(optval);
383 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
384 &optlen) == -1) {
385 debug("getsockopt: %s", strerror(errno));
386 break;
387 }
388 if (optval != 0) {
389 errno = optval;
390 break;
391 }
392 result = 0;
393 unset_nonblock(sockfd); 381 unset_nonblock(sockfd);
394 break; 382 return 0;
395 default: 383 } else if (errno != EINPROGRESS)
396 /* Should not occur */ 384 return -1;
397 fatal("Bogus return (%d) from select()", rc);
398 }
399 385
400 free(fdset); 386 if (waitrfd(sockfd, timeoutp) == -1)
387 return -1;
401 388
402 done: 389 /* Completed or failed */
403 if (result == 0 && *timeoutp > 0) { 390 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
404 ms_subtract_diff(&t_start, timeoutp); 391 debug("getsockopt: %s", strerror(errno));
405 if (*timeoutp <= 0) { 392 return -1;
406 errno = ETIMEDOUT;
407 result = -1;
408 }
409 } 393 }
410 394 if (optval != 0) {
411 return (result); 395 errno = optval;
396 return -1;
397 }
398 unset_nonblock(sockfd);
399 return 0;
412} 400}
413 401
414/* 402/*
@@ -423,7 +411,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
423 * the daemon. 411 * the daemon.
424 */ 412 */
425static int 413static int
426ssh_connect_direct(const char *host, struct addrinfo *aitop, 414ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
427 struct sockaddr_storage *hostaddr, u_short port, int family, 415 struct sockaddr_storage *hostaddr, u_short port, int family,
428 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) 416 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
429{ 417{
@@ -497,40 +485,39 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop,
497 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 485 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
498 486
499 /* Set the connection. */ 487 /* Set the connection. */
500 packet_set_connection(sock, sock); 488 if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
489 return -1; /* ssh_packet_set_connection logs error */
501 490
502 return 0; 491 return 0;
503} 492}
504 493
505int 494int
506ssh_connect(const char *host, struct addrinfo *addrs, 495ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs,
507 struct sockaddr_storage *hostaddr, u_short port, int family, 496 struct sockaddr_storage *hostaddr, u_short port, int family,
508 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) 497 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
509{ 498{
510 if (options.proxy_command == NULL) { 499 if (options.proxy_command == NULL) {
511 return ssh_connect_direct(host, addrs, hostaddr, port, family, 500 return ssh_connect_direct(ssh, host, addrs, hostaddr, port,
512 connection_attempts, timeout_ms, want_keepalive, needpriv); 501 family, connection_attempts, timeout_ms, want_keepalive,
502 needpriv);
513 } else if (strcmp(options.proxy_command, "-") == 0) { 503 } else if (strcmp(options.proxy_command, "-") == 0) {
514 packet_set_connection(STDIN_FILENO, STDOUT_FILENO); 504 if ((ssh_packet_set_connection(ssh,
515 return 0; /* Always succeeds */ 505 STDIN_FILENO, STDOUT_FILENO)) == NULL)
506 return -1; /* ssh_packet_set_connection logs error */
507 return 0;
516 } else if (options.proxy_use_fdpass) { 508 } else if (options.proxy_use_fdpass) {
517 return ssh_proxy_fdpass_connect(host, port, 509 return ssh_proxy_fdpass_connect(ssh, host, port,
518 options.proxy_command); 510 options.proxy_command);
519 } 511 }
520 return ssh_proxy_connect(host, port, options.proxy_command); 512 return ssh_proxy_connect(ssh, host, port, options.proxy_command);
521} 513}
522 514
523static void 515static void
524send_client_banner(int connection_out, int minor1) 516send_client_banner(int connection_out, int minor1)
525{ 517{
526 /* Send our own protocol version identification. */ 518 /* Send our own protocol version identification. */
527 if (compat20) { 519 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
528 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", 520 PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE);
529 PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE);
530 } else {
531 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
532 PROTOCOL_MAJOR_1, minor1, SSH_RELEASE);
533 }
534 if (atomicio(vwrite, connection_out, client_version_string, 521 if (atomicio(vwrite, connection_out, client_version_string,
535 strlen(client_version_string)) != strlen(client_version_string)) 522 strlen(client_version_string)) != strlen(client_version_string))
536 fatal("write: %.100s", strerror(errno)); 523 fatal("write: %.100s", strerror(errno));
@@ -549,50 +536,27 @@ ssh_exchange_identification(int timeout_ms)
549 int remote_major, remote_minor, mismatch; 536 int remote_major, remote_minor, mismatch;
550 int connection_in = packet_get_connection_in(); 537 int connection_in = packet_get_connection_in();
551 int connection_out = packet_get_connection_out(); 538 int connection_out = packet_get_connection_out();
552 int minor1 = PROTOCOL_MINOR_1, client_banner_sent = 0;
553 u_int i, n; 539 u_int i, n;
554 size_t len; 540 size_t len;
555 int fdsetsz, remaining, rc; 541 int rc;
556 struct timeval t_start, t_remaining;
557 fd_set *fdset;
558
559 fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
560 fdset = xcalloc(1, fdsetsz);
561 542
562 /* 543 send_client_banner(connection_out, 0);
563 * If we are SSH2-only then we can send the banner immediately and
564 * save a round-trip.
565 */
566 if (options.protocol == SSH_PROTO_2) {
567 enable_compat20();
568 send_client_banner(connection_out, 0);
569 client_banner_sent = 1;
570 }
571 544
572 /* Read other side's version identification. */ 545 /* Read other side's version identification. */
573 remaining = timeout_ms;
574 for (n = 0;;) { 546 for (n = 0;;) {
575 for (i = 0; i < sizeof(buf) - 1; i++) { 547 for (i = 0; i < sizeof(buf) - 1; i++) {
576 if (timeout_ms > 0) { 548 if (timeout_ms > 0) {
577 gettimeofday(&t_start, NULL); 549 rc = waitrfd(connection_in, &timeout_ms);
578 ms_to_timeval(&t_remaining, remaining); 550 if (rc == -1 && errno == ETIMEDOUT) {
579 FD_SET(connection_in, fdset);
580 rc = select(connection_in + 1, fdset, NULL,
581 fdset, &t_remaining);
582 ms_subtract_diff(&t_start, &remaining);
583 if (rc == 0 || remaining <= 0)
584 fatal("Connection timed out during " 551 fatal("Connection timed out during "
585 "banner exchange"); 552 "banner exchange");
586 if (rc == -1) { 553 } else if (rc == -1) {
587 if (errno == EINTR) 554 fatal("%s: %s",
588 continue; 555 __func__, strerror(errno));
589 fatal("ssh_exchange_identification: "
590 "select: %s", strerror(errno));
591 } 556 }
592 } 557 }
593 558
594 len = atomicio(read, connection_in, &buf[i], 1); 559 len = atomicio(read, connection_in, &buf[i], 1);
595
596 if (len != 1 && errno == EPIPE) 560 if (len != 1 && errno == EPIPE)
597 fatal("ssh_exchange_identification: " 561 fatal("ssh_exchange_identification: "
598 "Connection closed by remote host"); 562 "Connection closed by remote host");
@@ -618,7 +582,6 @@ ssh_exchange_identification(int timeout_ms)
618 debug("ssh_exchange_identification: %s", buf); 582 debug("ssh_exchange_identification: %s", buf);
619 } 583 }
620 server_version_string = xstrdup(buf); 584 server_version_string = xstrdup(buf);
621 free(fdset);
622 585
623 /* 586 /*
624 * Check that the versions match. In future this might accept 587 * Check that the versions match. In future this might accept
@@ -634,51 +597,25 @@ ssh_exchange_identification(int timeout_ms)
634 mismatch = 0; 597 mismatch = 0;
635 598
636 switch (remote_major) { 599 switch (remote_major) {
600 case 2:
601 break;
637 case 1: 602 case 1:
638 if (remote_minor == 99 && 603 if (remote_minor != 99)
639 (options.protocol & SSH_PROTO_2) &&
640 !(options.protocol & SSH_PROTO_1_PREFERRED)) {
641 enable_compat20();
642 break;
643 }
644 if (!(options.protocol & SSH_PROTO_1)) {
645 mismatch = 1; 604 mismatch = 1;
646 break;
647 }
648 if (remote_minor < 3) {
649 fatal("Remote machine has too old SSH software version.");
650 } else if (remote_minor == 3 || remote_minor == 4) {
651 /* We speak 1.3, too. */
652 enable_compat13();
653 minor1 = 3;
654 if (options.forward_agent) {
655 logit("Agent forwarding disabled for protocol 1.3");
656 options.forward_agent = 0;
657 }
658 }
659 break; 605 break;
660 case 2:
661 if (options.protocol & SSH_PROTO_2) {
662 enable_compat20();
663 break;
664 }
665 /* FALLTHROUGH */
666 default: 606 default:
667 mismatch = 1; 607 mismatch = 1;
668 break; 608 break;
669 } 609 }
670 if (mismatch) 610 if (mismatch)
671 fatal("Protocol major versions differ: %d vs. %d", 611 fatal("Protocol major versions differ: %d vs. %d",
672 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 612 PROTOCOL_MAJOR_2, remote_major);
673 remote_major);
674 if ((datafellows & SSH_BUG_DERIVEKEY) != 0) 613 if ((datafellows & SSH_BUG_DERIVEKEY) != 0)
675 fatal("Server version \"%.100s\" uses unsafe key agreement; " 614 fatal("Server version \"%.100s\" uses unsafe key agreement; "
676 "refusing connection", remote_version); 615 "refusing connection", remote_version);
677 if ((datafellows & SSH_BUG_RSASIGMD5) != 0) 616 if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
678 logit("Server version \"%.100s\" uses unsafe RSA signature " 617 logit("Server version \"%.100s\" uses unsafe RSA signature "
679 "scheme; disabling use of RSA keys", remote_version); 618 "scheme; disabling use of RSA keys", remote_version);
680 if (!client_banner_sent)
681 send_client_banner(connection_out, minor1);
682 chop(server_version_string); 619 chop(server_version_string);
683} 620}
684 621
@@ -707,7 +644,7 @@ confirm(const char *prompt)
707} 644}
708 645
709static int 646static int
710check_host_cert(const char *host, const Key *host_key) 647check_host_cert(const char *host, const struct sshkey *host_key)
711{ 648{
712 const char *reason; 649 const char *reason;
713 650
@@ -805,13 +742,13 @@ get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
805#define ROQUIET 2 742#define ROQUIET 2
806static int 743static int
807check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, 744check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
808 Key *host_key, int readonly, 745 struct sshkey *host_key, int readonly,
809 char **user_hostfiles, u_int num_user_hostfiles, 746 char **user_hostfiles, u_int num_user_hostfiles,
810 char **system_hostfiles, u_int num_system_hostfiles) 747 char **system_hostfiles, u_int num_system_hostfiles)
811{ 748{
812 HostStatus host_status; 749 HostStatus host_status;
813 HostStatus ip_status; 750 HostStatus ip_status;
814 Key *raw_key = NULL; 751 struct sshkey *raw_key = NULL;
815 char *ip = NULL, *host = NULL; 752 char *ip = NULL, *host = NULL;
816 char hostline[1000], *hostp, *fp, *ra; 753 char hostline[1000], *hostp, *fp, *ra;
817 char msg[1024]; 754 char msg[1024];
@@ -819,7 +756,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
819 const struct hostkey_entry *host_found, *ip_found; 756 const struct hostkey_entry *host_found, *ip_found;
820 int len, cancelled_forwarding = 0; 757 int len, cancelled_forwarding = 0;
821 int local = sockaddr_is_local(hostaddr); 758 int local = sockaddr_is_local(hostaddr);
822 int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; 759 int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0;
823 int hostkey_trusted = 0; /* Known or explicitly accepted by user */ 760 int hostkey_trusted = 0; /* Known or explicitly accepted by user */
824 struct hostkeys *host_hostkeys, *ip_hostkeys; 761 struct hostkeys *host_hostkeys, *ip_hostkeys;
825 u_int i; 762 u_int i;
@@ -870,8 +807,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
870 807
871 retry: 808 retry:
872 /* Reload these as they may have changed on cert->key downgrade */ 809 /* Reload these as they may have changed on cert->key downgrade */
873 want_cert = key_is_cert(host_key); 810 want_cert = sshkey_is_cert(host_key);
874 type = key_type(host_key); 811 type = sshkey_type(host_key);
875 812
876 /* 813 /*
877 * Check if the host key is present in the user's list of known 814 * Check if the host key is present in the user's list of known
@@ -891,7 +828,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
891 if (host_status == HOST_CHANGED && 828 if (host_status == HOST_CHANGED &&
892 (ip_status != HOST_CHANGED || 829 (ip_status != HOST_CHANGED ||
893 (ip_found != NULL && 830 (ip_found != NULL &&
894 !key_equal(ip_found->key, host_found->key)))) 831 !sshkey_equal(ip_found->key, host_found->key))))
895 host_ip_differ = 1; 832 host_ip_differ = 1;
896 } else 833 } else
897 ip_status = host_status; 834 ip_status = host_status;
@@ -903,7 +840,9 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
903 host, type, want_cert ? "certificate" : "key"); 840 host, type, want_cert ? "certificate" : "key");
904 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", 841 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
905 host_found->file, host_found->line); 842 host_found->file, host_found->line);
906 if (want_cert && !check_host_cert(hostname, host_key)) 843 if (want_cert &&
844 !check_host_cert(options.host_key_alias == NULL ?
845 hostname : options.host_key_alias, host_key))
907 goto fail; 846 goto fail;
908 if (options.check_host_ip && ip_status == HOST_NEW) { 847 if (options.check_host_ip && ip_status == HOST_NEW) {
909 if (readonly || want_cert) 848 if (readonly || want_cert)
@@ -947,7 +886,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
947 if (readonly || want_cert) 886 if (readonly || want_cert)
948 goto fail; 887 goto fail;
949 /* The host is new. */ 888 /* The host is new. */
950 if (options.strict_host_key_checking == 1) { 889 if (options.strict_host_key_checking ==
890 SSH_STRICT_HOSTKEY_YES) {
951 /* 891 /*
952 * User has requested strict host key checking. We 892 * User has requested strict host key checking. We
953 * will not add the host key automatically. The only 893 * will not add the host key automatically. The only
@@ -956,7 +896,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
956 error("No %s host key is known for %.200s and you " 896 error("No %s host key is known for %.200s and you "
957 "have requested strict checking.", type, host); 897 "have requested strict checking.", type, host);
958 goto fail; 898 goto fail;
959 } else if (options.strict_host_key_checking == 2) { 899 } else if (options.strict_host_key_checking ==
900 SSH_STRICT_HOSTKEY_ASK) {
960 char msg1[1024], msg2[1024]; 901 char msg1[1024], msg2[1024];
961 902
962 if (show_other_keys(host_hostkeys, host_key)) 903 if (show_other_keys(host_hostkeys, host_key))
@@ -1000,8 +941,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1000 hostkey_trusted = 1; /* user explicitly confirmed */ 941 hostkey_trusted = 1; /* user explicitly confirmed */
1001 } 942 }
1002 /* 943 /*
1003 * If not in strict mode, add the key automatically to the 944 * If in "new" or "off" strict mode, add the key automatically
1004 * local known_hosts file. 945 * to the local known_hosts file.
1005 */ 946 */
1006 if (options.check_host_ip && ip_status == HOST_NEW) { 947 if (options.check_host_ip && ip_status == HOST_NEW) {
1007 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 948 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
@@ -1043,7 +984,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1043 * If strict host key checking is in use, the user will have 984 * If strict host key checking is in use, the user will have
1044 * to edit the key manually and we can only abort. 985 * to edit the key manually and we can only abort.
1045 */ 986 */
1046 if (options.strict_host_key_checking) { 987 if (options.strict_host_key_checking !=
988 SSH_STRICT_HOSTKEY_OFF) {
1047 error("%s host key for %.200s was revoked and you have " 989 error("%s host key for %.200s was revoked and you have "
1048 "requested strict checking.", type, host); 990 "requested strict checking.", type, host);
1049 goto fail; 991 goto fail;
@@ -1092,7 +1034,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1092 warn_changed_key(host_key); 1034 warn_changed_key(host_key);
1093 error("Add correct host key in %.100s to get rid of this message.", 1035 error("Add correct host key in %.100s to get rid of this message.",
1094 user_hostfiles[0]); 1036 user_hostfiles[0]);
1095 error("Offending %s key in %s:%lu", key_type(host_found->key), 1037 error("Offending %s key in %s:%lu",
1038 sshkey_type(host_found->key),
1096 host_found->file, host_found->line); 1039 host_found->file, host_found->line);
1097 error(" remove with:"); 1040 error(" remove with:");
1098 error(" ssh-keygen -f \"%s\" -R \"%s\"", 1041 error(" ssh-keygen -f \"%s\" -R \"%s\"",
@@ -1102,7 +1045,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1102 * If strict host key checking is in use, the user will have 1045 * If strict host key checking is in use, the user will have
1103 * to edit the key manually and we can only abort. 1046 * to edit the key manually and we can only abort.
1104 */ 1047 */
1105 if (options.strict_host_key_checking) { 1048 if (options.strict_host_key_checking !=
1049 SSH_STRICT_HOSTKEY_OFF) {
1106 error("%s host key for %.200s has changed and you have " 1050 error("%s host key for %.200s has changed and you have "
1107 "requested strict checking.", type, host); 1051 "requested strict checking.", type, host);
1108 goto fail; 1052 goto fail;
@@ -1189,15 +1133,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1189 "\nMatching host key in %s:%lu", 1133 "\nMatching host key in %s:%lu",
1190 host_found->file, host_found->line); 1134 host_found->file, host_found->line);
1191 } 1135 }
1192 if (options.strict_host_key_checking == 1) { 1136 if (options.strict_host_key_checking ==
1193 logit("%s", msg); 1137 SSH_STRICT_HOSTKEY_ASK) {
1194 error("Exiting, you have requested strict checking.");
1195 goto fail;
1196 } else if (options.strict_host_key_checking == 2) {
1197 strlcat(msg, "\nAre you sure you want " 1138 strlcat(msg, "\nAre you sure you want "
1198 "to continue connecting (yes/no)? ", sizeof(msg)); 1139 "to continue connecting (yes/no)? ", sizeof(msg));
1199 if (!confirm(msg)) 1140 if (!confirm(msg))
1200 goto fail; 1141 goto fail;
1142 } else if (options.strict_host_key_checking !=
1143 SSH_STRICT_HOSTKEY_OFF) {
1144 logit("%s", msg);
1145 error("Exiting, you have requested strict checking.");
1146 goto fail;
1201 } else { 1147 } else {
1202 logit("%s", msg); 1148 logit("%s", msg);
1203 } 1149 }
@@ -1224,14 +1170,16 @@ fail:
1224 * search normally. 1170 * search normally.
1225 */ 1171 */
1226 debug("No matching CA found. Retry with plain key"); 1172 debug("No matching CA found. Retry with plain key");
1227 raw_key = key_from_private(host_key); 1173 if ((r = sshkey_from_private(host_key, &raw_key)) != 0)
1228 if (key_drop_cert(raw_key) != 0) 1174 fatal("%s: sshkey_from_private: %s",
1229 fatal("Couldn't drop certificate"); 1175 __func__, ssh_err(r));
1176 if ((r = sshkey_drop_cert(raw_key)) != 0)
1177 fatal("Couldn't drop certificate: %s", ssh_err(r));
1230 host_key = raw_key; 1178 host_key = raw_key;
1231 goto retry; 1179 goto retry;
1232 } 1180 }
1233 if (raw_key != NULL) 1181 if (raw_key != NULL)
1234 key_free(raw_key); 1182 sshkey_free(raw_key);
1235 free(ip); 1183 free(ip);
1236 free(host); 1184 free(host);
1237 if (host_hostkeys != NULL) 1185 if (host_hostkeys != NULL)
@@ -1243,7 +1191,7 @@ fail:
1243 1191
1244/* returns 0 if key verifies or -1 if key does NOT verify */ 1192/* returns 0 if key verifies or -1 if key does NOT verify */
1245int 1193int
1246verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 1194verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key)
1247{ 1195{
1248 u_int i; 1196 u_int i;
1249 int r = -1, flags = 0; 1197 int r = -1, flags = 0;
@@ -1279,8 +1227,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1279 host_key->cert->principals[i]); 1227 host_key->cert->principals[i]);
1280 } 1228 }
1281 } else { 1229 } else {
1282 debug("Server host key: %s %s", compat20 ? 1230 debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp);
1283 sshkey_ssh_name(host_key) : sshkey_type(host_key), fp);
1284 } 1231 }
1285 1232
1286 if (sshkey_equal(previous_host_key, host_key)) { 1233 if (sshkey_equal(previous_host_key, host_key)) {
@@ -1348,8 +1295,8 @@ out:
1348 free(fp); 1295 free(fp);
1349 free(cafp); 1296 free(cafp);
1350 if (r == 0 && host_key != NULL) { 1297 if (r == 0 && host_key != NULL) {
1351 key_free(previous_host_key); 1298 sshkey_free(previous_host_key);
1352 previous_host_key = key_from_private(host_key); 1299 r = sshkey_from_private(host_key, &previous_host_key);
1353 } 1300 }
1354 1301
1355 return r; 1302 return r;
@@ -1385,17 +1332,8 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1385 /* key exchange */ 1332 /* key exchange */
1386 /* authenticate user */ 1333 /* authenticate user */
1387 debug("Authenticating to %s:%d as '%s'", host, port, server_user); 1334 debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1388 if (compat20) { 1335 ssh_kex2(host, hostaddr, port);
1389 ssh_kex2(host, hostaddr, port); 1336 ssh_userauth2(local_user, server_user, host, sensitive);
1390 ssh_userauth2(local_user, server_user, host, sensitive);
1391 } else {
1392#ifdef WITH_SSH1
1393 ssh_kex(host, hostaddr);
1394 ssh_userauth1(local_user, server_user, host, sensitive);
1395#else
1396 fatal("ssh1 is not supported");
1397#endif
1398 }
1399 free(local_user); 1337 free(local_user);
1400} 1338}
1401 1339
@@ -1419,10 +1357,9 @@ ssh_put_password(char *password)
1419 1357
1420/* print all known host keys for a given host, but skip keys of given type */ 1358/* print all known host keys for a given host, but skip keys of given type */
1421static int 1359static int
1422show_other_keys(struct hostkeys *hostkeys, Key *key) 1360show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
1423{ 1361{
1424 int type[] = { 1362 int type[] = {
1425 KEY_RSA1,
1426 KEY_RSA, 1363 KEY_RSA,
1427 KEY_DSA, 1364 KEY_DSA,
1428 KEY_ECDSA, 1365 KEY_ECDSA,
@@ -1460,7 +1397,7 @@ show_other_keys(struct hostkeys *hostkeys, Key *key)
1460} 1397}
1461 1398
1462static void 1399static void
1463warn_changed_key(Key *host_key) 1400warn_changed_key(struct sshkey *host_key)
1464{ 1401{
1465 char *fp; 1402 char *fp;
1466 1403
@@ -1523,7 +1460,7 @@ ssh_local_cmd(const char *args)
1523} 1460}
1524 1461
1525void 1462void
1526maybe_add_key_to_agent(char *authfile, Key *private, char *comment, 1463maybe_add_key_to_agent(char *authfile, struct sshkey *private, char *comment,
1527 char *passphrase) 1464 char *passphrase)
1528{ 1465{
1529 int auth_sock = -1, r; 1466 int auth_sock = -1, r;