diff options
Diffstat (limited to 'crypto/openssh/sshconnect.c')
-rw-r--r-- | crypto/openssh/sshconnect.c | 164 |
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! @"); |