summaryrefslogtreecommitdiff
path: root/crypto/openssh/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/sshconnect.c')
-rw-r--r--crypto/openssh/sshconnect.c164
1 files changed, 106 insertions, 58 deletions
diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c
index 102c0bdae257..11a9cf651cb6 100644
--- a/crypto/openssh/sshconnect.c
+++ b/crypto/openssh/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.246 2014/02/06 22:21:01 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.263 2015/08/20 22:32:42 deraadt Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -16,6 +16,7 @@
#include "includes.h"
__RCSID("$FreeBSD$");
+#include <sys/param.h> /* roundup */
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
@@ -56,17 +57,20 @@ __RCSID("$FreeBSD$");
#include "sshconnect.h"
#include "hostfile.h"
#include "log.h"
+#include "misc.h"
#include "readconf.h"
#include "atomicio.h"
-#include "misc.h"
#include "dns.h"
#include "roaming.h"
#include "monitor_fdpass.h"
#include "ssh2.h"
#include "version.h"
+#include "authfile.h"
+#include "ssherr.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
+Key *previous_host_key = NULL;
static int matching_host_key_dns = 0;
@@ -265,29 +269,6 @@ ssh_kill_proxy_command(void)
}
/*
- * Set TCP receive buffer if requested.
- * Note: tuning needs to happen after the socket is created but before the
- * connection happens so winscale is negotiated properly.
- */
-static void
-ssh_set_socket_recvbuf(int sock)
-{
- void *buf = (void *)&options.tcp_rcv_buf;
- int socksize, sz = sizeof(options.tcp_rcv_buf);
- socklen_t len = sizeof(int);
-
- debug("setsockopt attempting to set SO_RCVBUF to %d",
- options.tcp_rcv_buf);
- if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) {
- getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &len);
- debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno),
- socksize);
- } else
- error("Couldn't set socket receive buffer to %d: %.100s",
- options.tcp_rcv_buf, strerror(errno));
-}
-
-/*
* Creates a (possibly privileged) socket for use as the ssh connection.
*/
static int
@@ -303,9 +284,6 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
}
fcntl(sock, F_SETFD, FD_CLOEXEC);
- if (options.tcp_rcv_buf > 0)
- ssh_set_socket_recvbuf(sock);
-
/* Bind the socket to an alternative local IP address */
if (options.bind_address == NULL && !privileged)
return sock;
@@ -380,7 +358,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
goto done;
}
- fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
+ fdset = xcalloc(howmany(sockfd + 1, NFDBITS),
sizeof(fd_mask));
FD_SET(sockfd, fdset);
ms_to_timeval(&tv, *timeoutp);
@@ -546,10 +524,10 @@ static void
send_client_banner(int connection_out, int minor1)
{
/* Send our own protocol version identification. */
- xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s%s%s%s",
+ xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s%s%s",
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
compat20 ? PROTOCOL_MINOR_2 : minor1,
- SSH_VERSION, options.hpn_disabled ? "" : SSH_VERSION_HPN,
+ SSH_VERSION,
*options.version_addendum == '\0' ? "" : " ",
options.version_addendum, compat20 ? "\r\n" : "\n");
if (roaming_atomicio(vwrite, connection_out, client_version_string,
@@ -651,7 +629,7 @@ ssh_exchange_identification(int timeout_ms)
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
- compat_datafellows(remote_version);
+ active_state->compat = compat_datafellows(remote_version);
mismatch = 0;
switch (remote_major) {
@@ -736,7 +714,7 @@ check_host_cert(const char *host, const Key *host_key)
error("%s", reason);
return 0;
}
- if (buffer_len(&host_key->cert->critical) != 0) {
+ if (buffer_len(host_key->cert->critical) != 0) {
error("Certificate for %s contains unsupported "
"critical options(s)", host);
return 0;
@@ -793,7 +771,7 @@ get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
if (options.proxy_command == NULL) {
if (getnameinfo(hostaddr, addrlen,
ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
- fatal("check_host_key: getnameinfo failed");
+ fatal("%s: getnameinfo failed", __func__);
*hostfile_ipaddr = put_host_port(ntop, port);
} else {
*hostfile_ipaddr = xstrdup("<no hostip for proxy "
@@ -841,6 +819,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
int len, cancelled_forwarding = 0;
int local = sockaddr_is_local(hostaddr);
int r, want_cert = key_is_cert(host_key), host_ip_differ = 0;
+ int hostkey_trusted = 0; /* Known or explicitly accepted by user */
struct hostkeys *host_hostkeys, *ip_hostkeys;
u_int i;
@@ -934,20 +913,24 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
host_key, options.hash_known_hosts))
logit("Failed to add the %s host key for IP "
"address '%.128s' to the list of known "
- "hosts (%.30s).", type, ip,
+ "hosts (%.500s).", type, ip,
user_hostfiles[0]);
else
logit("Warning: Permanently added the %s host "
"key for IP address '%.128s' to the list "
"of known hosts.", type, ip);
} else if (options.visual_host_key) {
- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
- ra = key_fingerprint(host_key, SSH_FP_MD5,
- SSH_FP_RANDOMART);
+ fp = sshkey_fingerprint(host_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT);
+ ra = sshkey_fingerprint(host_key,
+ options.fingerprint_hash, SSH_FP_RANDOMART);
+ if (fp == NULL || ra == NULL)
+ fatal("%s: sshkey_fingerprint fail", __func__);
logit("Host key fingerprint is %s\n%s\n", fp, ra);
free(ra);
free(fp);
}
+ hostkey_trusted = 1;
break;
case HOST_NEW:
if (options.host_key_alias == NULL && port != 0 &&
@@ -982,9 +965,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
else
snprintf(msg1, sizeof(msg1), ".");
/* The default */
- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
- ra = key_fingerprint(host_key, SSH_FP_MD5,
- SSH_FP_RANDOMART);
+ fp = sshkey_fingerprint(host_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT);
+ ra = sshkey_fingerprint(host_key,
+ options.fingerprint_hash, SSH_FP_RANDOMART);
+ if (fp == NULL || ra == NULL)
+ fatal("%s: sshkey_fingerprint fail", __func__);
msg2[0] = '\0';
if (options.verify_host_key_dns) {
if (matching_host_key_dns)
@@ -1010,6 +996,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
free(fp);
if (!confirm(msg))
goto fail;
+ hostkey_trusted = 1; /* user explicitly confirmed */
}
/*
* If not in strict mode, add the key automatically to the
@@ -1208,6 +1195,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
}
}
+ if (!hostkey_trusted && options.update_hostkeys) {
+ debug("%s: hostkey not known or explicitly trusted: "
+ "disabling UpdateHostkeys", __func__);
+ options.update_hostkeys = 0;
+ }
+
free(ip);
free(host);
if (host_hostkeys != NULL)
@@ -1244,29 +1237,64 @@ fail:
int
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
- int flags = 0;
- char *fp;
- Key *plain = NULL;
+ int r = -1, flags = 0;
+ char *fp = NULL;
+ struct sshkey *plain = NULL;
+
+ if ((fp = sshkey_fingerprint(host_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
+ error("%s: fingerprint host key: %s", __func__, ssh_err(r));
+ r = -1;
+ goto out;
+ }
- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
- debug("Server host key: %s %s", key_type(host_key), fp);
- free(fp);
+ debug("Server host key: %s %s",
+ compat20 ? sshkey_ssh_name(host_key) : sshkey_type(host_key), fp);
+
+ if (sshkey_equal(previous_host_key, host_key)) {
+ debug2("%s: server host key %s %s matches cached key",
+ __func__, sshkey_type(host_key), fp);
+ r = 0;
+ goto out;
+ }
+
+ /* Check in RevokedHostKeys file if specified */
+ if (options.revoked_host_keys != NULL) {
+ r = sshkey_check_revoked(host_key, options.revoked_host_keys);
+ switch (r) {
+ case 0:
+ break; /* not revoked */
+ case SSH_ERR_KEY_REVOKED:
+ error("Host key %s %s revoked by file %s",
+ sshkey_type(host_key), fp,
+ options.revoked_host_keys);
+ r = -1;
+ goto out;
+ default:
+ error("Error checking host key %s %s in "
+ "revoked keys file %s: %s", sshkey_type(host_key),
+ fp, options.revoked_host_keys, ssh_err(r));
+ r = -1;
+ goto out;
+ }
+ }
if (options.verify_host_key_dns) {
/*
* XXX certs are not yet supported for DNS, so downgrade
* them and try the plain key.
*/
- plain = key_from_private(host_key);
- if (key_is_cert(plain))
- key_drop_cert(plain);
+ if ((r = sshkey_from_private(host_key, &plain)) != 0)
+ goto out;
+ if (sshkey_is_cert(plain))
+ sshkey_drop_cert(plain);
if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
if (flags & DNS_VERIFY_FOUND) {
if (options.verify_host_key_dns == 1 &&
flags & DNS_VERIFY_MATCH &&
flags & DNS_VERIFY_SECURE) {
- key_free(plain);
- return 0;
+ r = 0;
+ goto out;
}
if (flags & DNS_VERIFY_MATCH) {
matching_host_key_dns = 1;
@@ -1278,12 +1306,20 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
}
}
}
- key_free(plain);
}
-
- return check_host_key(host, hostaddr, options.port, host_key, RDRW,
+ r = check_host_key(host, hostaddr, options.port, host_key, RDRW,
options.user_hostfiles, options.num_user_hostfiles,
options.system_hostfiles, options.num_system_hostfiles);
+
+out:
+ sshkey_free(plain);
+ free(fp);
+ if (r == 0 && host_key != NULL) {
+ key_free(previous_host_key);
+ previous_host_key = key_from_private(host_key);
+ }
+
+ return r;
}
/*
@@ -1315,12 +1351,17 @@ ssh_login(Sensitive *sensitive, const char *orighost,
/* key exchange */
/* authenticate user */
+ debug("Authenticating to %s:%d as '%s'", host, port, server_user);
if (compat20) {
ssh_kex2(host, hostaddr, port);
ssh_userauth2(local_user, server_user, host, sensitive);
} else {
+#ifdef WITH_SSH1
ssh_kex(host, hostaddr);
ssh_userauth1(local_user, server_user, host, sensitive);
+#else
+ fatal("ssh1 is not supported");
+#endif
}
free(local_user);
}
@@ -1364,8 +1405,12 @@ show_other_keys(struct hostkeys *hostkeys, Key *key)
continue;
if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
continue;
- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
+ fp = sshkey_fingerprint(found->key,
+ options.fingerprint_hash, SSH_FP_DEFAULT);
+ ra = sshkey_fingerprint(found->key,
+ options.fingerprint_hash, SSH_FP_RANDOMART);
+ if (fp == NULL || ra == NULL)
+ fatal("%s: sshkey_fingerprint fail", __func__);
logit("WARNING: %s key found for host %s\n"
"in %s:%lu\n"
"%s key fingerprint %s.",
@@ -1386,7 +1431,10 @@ warn_changed_key(Key *host_key)
{
char *fp;
- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+ fp = sshkey_fingerprint(host_key, options.fingerprint_hash,
+ SSH_FP_DEFAULT);
+ if (fp == NULL)
+ fatal("%s: sshkey_fingerprint fail", __func__);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");