summaryrefslogtreecommitdiff
path: root/clientloop.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2015-08-19 14:23:50 +0100
committerColin Watson <cjwatson@debian.org>2015-08-19 14:23:50 +0100
commitbaccdb349b31c47cd76fb63211f754ed33a9707e (patch)
treed03653f975fd4eb8bf71bb0c9d168614401202fa /clientloop.c
parent487bdb3a5ef6075887b830ccb8a0b14f6da78e93 (diff)
parent9f82e5a9042f2d872e98f48a876fcab3e25dd9bb (diff)
Import openssh_6.8p1.orig.tar.gz
Diffstat (limited to 'clientloop.c')
-rw-r--r--clientloop.c455
1 files changed, 424 insertions, 31 deletions
diff --git a/clientloop.c b/clientloop.c
index 397c96532..a9c8a90f0 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.272 2015/02/25 19:54:02 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
@@ -61,9 +61,9 @@
61 61
62#include "includes.h" 62#include "includes.h"
63 63
64#include <sys/param.h> /* MIN MAX */
64#include <sys/types.h> 65#include <sys/types.h>
65#include <sys/ioctl.h> 66#include <sys/ioctl.h>
66#include <sys/param.h>
67#ifdef HAVE_SYS_STAT_H 67#ifdef HAVE_SYS_STAT_H
68# include <sys/stat.h> 68# include <sys/stat.h>
69#endif 69#endif
@@ -85,6 +85,7 @@
85#include <termios.h> 85#include <termios.h>
86#include <pwd.h> 86#include <pwd.h>
87#include <unistd.h> 87#include <unistd.h>
88#include <limits.h>
88 89
89#include "openbsd-compat/sys-queue.h" 90#include "openbsd-compat/sys-queue.h"
90#include "xmalloc.h" 91#include "xmalloc.h"
@@ -110,6 +111,8 @@
110#include "match.h" 111#include "match.h"
111#include "msg.h" 112#include "msg.h"
112#include "roaming.h" 113#include "roaming.h"
114#include "ssherr.h"
115#include "hostfile.h"
113 116
114/* import options */ 117/* import options */
115extern Options options; 118extern Options options;
@@ -191,9 +194,6 @@ TAILQ_HEAD(global_confirms, global_confirm);
191static struct global_confirms global_confirms = 194static struct global_confirms global_confirms =
192 TAILQ_HEAD_INITIALIZER(global_confirms); 195 TAILQ_HEAD_INITIALIZER(global_confirms);
193 196
194/*XXX*/
195extern Kex *xxx_kex;
196
197void ssh_process_session2_setup(int, int, int, Buffer *); 197void ssh_process_session2_setup(int, int, int, Buffer *);
198 198
199/* Restores stdin to blocking mode. */ 199/* Restores stdin to blocking mode. */
@@ -341,12 +341,12 @@ client_x11_get_proto(const char *display, const char *xauth_path,
341 display = xdisplay; 341 display = xdisplay;
342 } 342 }
343 if (trusted == 0) { 343 if (trusted == 0) {
344 xauthdir = xmalloc(MAXPATHLEN); 344 xauthdir = xmalloc(PATH_MAX);
345 xauthfile = xmalloc(MAXPATHLEN); 345 xauthfile = xmalloc(PATH_MAX);
346 mktemp_proto(xauthdir, MAXPATHLEN); 346 mktemp_proto(xauthdir, PATH_MAX);
347 if (mkdtemp(xauthdir) != NULL) { 347 if (mkdtemp(xauthdir) != NULL) {
348 do_unlink = 1; 348 do_unlink = 1;
349 snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", 349 snprintf(xauthfile, PATH_MAX, "%s/xauthfile",
350 xauthdir); 350 xauthdir);
351 snprintf(cmd, sizeof(cmd), 351 snprintf(cmd, sizeof(cmd),
352 "%s -f %s generate %s " SSH_X11_PROTO 352 "%s -f %s generate %s " SSH_X11_PROTO
@@ -538,13 +538,13 @@ client_check_window_change(void)
538 } 538 }
539} 539}
540 540
541static void 541static int
542client_global_request_reply(int type, u_int32_t seq, void *ctxt) 542client_global_request_reply(int type, u_int32_t seq, void *ctxt)
543{ 543{
544 struct global_confirm *gc; 544 struct global_confirm *gc;
545 545
546 if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) 546 if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
547 return; 547 return 0;
548 if (gc->cb != NULL) 548 if (gc->cb != NULL)
549 gc->cb(type, seq, gc->ctx); 549 gc->cb(type, seq, gc->ctx);
550 if (--gc->ref_count <= 0) { 550 if (--gc->ref_count <= 0) {
@@ -554,6 +554,7 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt)
554 } 554 }
555 555
556 packet_set_alive_timeouts(0); 556 packet_set_alive_timeouts(0);
557 return 0;
557} 558}
558 559
559static void 560static void
@@ -1414,8 +1415,7 @@ client_process_output(fd_set *writeset)
1414static void 1415static void
1415client_process_buffered_input_packets(void) 1416client_process_buffered_input_packets(void)
1416{ 1417{
1417 dispatch_run(DISPATCH_NONBLOCK, &quit_pending, 1418 dispatch_run(DISPATCH_NONBLOCK, &quit_pending, active_state);
1418 compat20 ? xxx_kex : NULL);
1419} 1419}
1420 1420
1421/* scan buf[] for '~' before sending data to the peer */ 1421/* scan buf[] for '~' before sending data to the peer */
@@ -1469,7 +1469,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1469{ 1469{
1470 fd_set *readset = NULL, *writeset = NULL; 1470 fd_set *readset = NULL, *writeset = NULL;
1471 double start_time, total_time; 1471 double start_time, total_time;
1472 int max_fd = 0, max_fd2 = 0, len, rekeying = 0; 1472 int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0;
1473 u_int64_t ibytes, obytes; 1473 u_int64_t ibytes, obytes;
1474 u_int nalloc = 0; 1474 u_int nalloc = 0;
1475 char buf[100]; 1475 char buf[100];
@@ -1554,7 +1554,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1554 if (compat20 && session_closed && !channel_still_open()) 1554 if (compat20 && session_closed && !channel_still_open())
1555 break; 1555 break;
1556 1556
1557 rekeying = (xxx_kex != NULL && !xxx_kex->done); 1557 rekeying = (active_state->kex != NULL && !active_state->kex->done);
1558 1558
1559 if (rekeying) { 1559 if (rekeying) {
1560 debug("rekeying in progress"); 1560 debug("rekeying in progress");
@@ -1598,8 +1598,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1598 channel_after_select(readset, writeset); 1598 channel_after_select(readset, writeset);
1599 if (need_rekeying || packet_need_rekeying()) { 1599 if (need_rekeying || packet_need_rekeying()) {
1600 debug("need rekeying"); 1600 debug("need rekeying");
1601 xxx_kex->done = 0; 1601 active_state->kex->done = 0;
1602 kex_send_kexinit(xxx_kex); 1602 if ((r = kex_send_kexinit(active_state)) != 0)
1603 fatal("%s: kex_send_kexinit: %s",
1604 __func__, ssh_err(r));
1603 need_rekeying = 0; 1605 need_rekeying = 0;
1604 } 1606 }
1605 } 1607 }
@@ -1728,8 +1730,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1728 1730
1729 /* Report bytes transferred, and transfer rates. */ 1731 /* Report bytes transferred, and transfer rates. */
1730 total_time = get_current_time() - start_time; 1732 total_time = get_current_time() - start_time;
1731 packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); 1733 packet_get_bytes(&ibytes, &obytes);
1732 packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
1733 verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds", 1734 verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
1734 (unsigned long long)obytes, (unsigned long long)ibytes, total_time); 1735 (unsigned long long)obytes, (unsigned long long)ibytes, total_time);
1735 if (total_time > 0) 1736 if (total_time > 0)
@@ -1742,7 +1743,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1742 1743
1743/*********/ 1744/*********/
1744 1745
1745static void 1746static int
1746client_input_stdout_data(int type, u_int32_t seq, void *ctxt) 1747client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
1747{ 1748{
1748 u_int data_len; 1749 u_int data_len;
@@ -1751,8 +1752,9 @@ client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
1751 buffer_append(&stdout_buffer, data, data_len); 1752 buffer_append(&stdout_buffer, data, data_len);
1752 explicit_bzero(data, data_len); 1753 explicit_bzero(data, data_len);
1753 free(data); 1754 free(data);
1755 return 0;
1754} 1756}
1755static void 1757static int
1756client_input_stderr_data(int type, u_int32_t seq, void *ctxt) 1758client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
1757{ 1759{
1758 u_int data_len; 1760 u_int data_len;
@@ -1761,8 +1763,9 @@ client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
1761 buffer_append(&stderr_buffer, data, data_len); 1763 buffer_append(&stderr_buffer, data, data_len);
1762 explicit_bzero(data, data_len); 1764 explicit_bzero(data, data_len);
1763 free(data); 1765 free(data);
1766 return 0;
1764} 1767}
1765static void 1768static int
1766client_input_exit_status(int type, u_int32_t seq, void *ctxt) 1769client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1767{ 1770{
1768 exit_status = packet_get_int(); 1771 exit_status = packet_get_int();
@@ -1777,12 +1780,14 @@ client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1777 packet_write_wait(); 1780 packet_write_wait();
1778 /* Flag that we want to exit. */ 1781 /* Flag that we want to exit. */
1779 quit_pending = 1; 1782 quit_pending = 1;
1783 return 0;
1780} 1784}
1781static void 1785
1786static int
1782client_input_agent_open(int type, u_int32_t seq, void *ctxt) 1787client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1783{ 1788{
1784 Channel *c = NULL; 1789 Channel *c = NULL;
1785 int remote_id, sock; 1790 int r, remote_id, sock;
1786 1791
1787 /* Read the remote channel number from the message. */ 1792 /* Read the remote channel number from the message. */
1788 remote_id = packet_get_int(); 1793 remote_id = packet_get_int();
@@ -1792,7 +1797,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1792 * Get a connection to the local authentication agent (this may again 1797 * Get a connection to the local authentication agent (this may again
1793 * get forwarded). 1798 * get forwarded).
1794 */ 1799 */
1795 sock = ssh_get_authentication_socket(); 1800 if ((r = ssh_get_authentication_socket(&sock)) != 0 &&
1801 r != SSH_ERR_AGENT_NOT_PRESENT)
1802 debug("%s: ssh_get_authentication_socket: %s",
1803 __func__, ssh_err(r));
1804
1796 1805
1797 /* 1806 /*
1798 * If we could not connect the agent, send an error message back to 1807 * If we could not connect the agent, send an error message back to
@@ -1817,6 +1826,7 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1817 packet_put_int(c->self); 1826 packet_put_int(c->self);
1818 } 1827 }
1819 packet_send(); 1828 packet_send();
1829 return 0;
1820} 1830}
1821 1831
1822static Channel * 1832static Channel *
@@ -1910,7 +1920,7 @@ static Channel *
1910client_request_agent(const char *request_type, int rchan) 1920client_request_agent(const char *request_type, int rchan)
1911{ 1921{
1912 Channel *c = NULL; 1922 Channel *c = NULL;
1913 int sock; 1923 int r, sock;
1914 1924
1915 if (!options.forward_agent) { 1925 if (!options.forward_agent) {
1916 error("Warning: ssh server tried agent forwarding."); 1926 error("Warning: ssh server tried agent forwarding.");
@@ -1918,9 +1928,12 @@ client_request_agent(const char *request_type, int rchan)
1918 "malicious server."); 1928 "malicious server.");
1919 return NULL; 1929 return NULL;
1920 } 1930 }
1921 sock = ssh_get_authentication_socket(); 1931 if ((r = ssh_get_authentication_socket(&sock)) != 0) {
1922 if (sock < 0) 1932 if (r != SSH_ERR_AGENT_NOT_PRESENT)
1933 debug("%s: ssh_get_authentication_socket: %s",
1934 __func__, ssh_err(r));
1923 return NULL; 1935 return NULL;
1936 }
1924 c = channel_new("authentication agent connection", 1937 c = channel_new("authentication agent connection",
1925 SSH_CHANNEL_OPEN, sock, sock, -1, 1938 SSH_CHANNEL_OPEN, sock, sock, -1,
1926 CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, 1939 CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
@@ -1974,7 +1987,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
1974} 1987}
1975 1988
1976/* XXXX move to generic input handler */ 1989/* XXXX move to generic input handler */
1977static void 1990static int
1978client_input_channel_open(int type, u_int32_t seq, void *ctxt) 1991client_input_channel_open(int type, u_int32_t seq, void *ctxt)
1979{ 1992{
1980 Channel *c = NULL; 1993 Channel *c = NULL;
@@ -2025,8 +2038,10 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
2025 packet_send(); 2038 packet_send();
2026 } 2039 }
2027 free(ctype); 2040 free(ctype);
2041 return 0;
2028} 2042}
2029static void 2043
2044static int
2030client_input_channel_req(int type, u_int32_t seq, void *ctxt) 2045client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2031{ 2046{
2032 Channel *c = NULL; 2047 Channel *c = NULL;
@@ -2071,18 +2086,395 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2071 packet_send(); 2086 packet_send();
2072 } 2087 }
2073 free(rtype); 2088 free(rtype);
2089 return 0;
2090}
2091
2092struct hostkeys_update_ctx {
2093 /* The hostname and (optionally) IP address string for the server */
2094 char *host_str, *ip_str;
2095
2096 /*
2097 * Keys received from the server and a flag for each indicating
2098 * whether they already exist in known_hosts.
2099 * keys_seen is filled in by hostkeys_find() and later (for new
2100 * keys) by client_global_hostkeys_private_confirm().
2101 */
2102 struct sshkey **keys;
2103 int *keys_seen;
2104 size_t nkeys;
2105
2106 size_t nnew;
2107
2108 /*
2109 * Keys that are in known_hosts, but were not present in the update
2110 * from the server (i.e. scheduled to be deleted).
2111 * Filled in by hostkeys_find().
2112 */
2113 struct sshkey **old_keys;
2114 size_t nold;
2115};
2116
2117static void
2118hostkeys_update_ctx_free(struct hostkeys_update_ctx *ctx)
2119{
2120 size_t i;
2121
2122 if (ctx == NULL)
2123 return;
2124 for (i = 0; i < ctx->nkeys; i++)
2125 sshkey_free(ctx->keys[i]);
2126 free(ctx->keys);
2127 free(ctx->keys_seen);
2128 for (i = 0; i < ctx->nold; i++)
2129 sshkey_free(ctx->old_keys[i]);
2130 free(ctx->old_keys);
2131 free(ctx->host_str);
2132 free(ctx->ip_str);
2133 free(ctx);
2134}
2135
2136static int
2137hostkeys_find(struct hostkey_foreach_line *l, void *_ctx)
2138{
2139 struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
2140 size_t i;
2141 struct sshkey **tmp;
2142
2143 if (l->status != HKF_STATUS_MATCHED || l->key == NULL ||
2144 l->key->type == KEY_RSA1)
2145 return 0;
2146
2147 /* Mark off keys we've already seen for this host */
2148 for (i = 0; i < ctx->nkeys; i++) {
2149 if (sshkey_equal(l->key, ctx->keys[i])) {
2150 debug3("%s: found %s key at %s:%ld", __func__,
2151 sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum);
2152 ctx->keys_seen[i] = 1;
2153 return 0;
2154 }
2155 }
2156 /* This line contained a key that not offered by the server */
2157 debug3("%s: deprecated %s key at %s:%ld", __func__,
2158 sshkey_ssh_name(l->key), l->path, l->linenum);
2159 if ((tmp = reallocarray(ctx->old_keys, ctx->nold + 1,
2160 sizeof(*ctx->old_keys))) == NULL)
2161 fatal("%s: reallocarray failed nold = %zu",
2162 __func__, ctx->nold);
2163 ctx->old_keys = tmp;
2164 ctx->old_keys[ctx->nold++] = l->key;
2165 l->key = NULL;
2166
2167 return 0;
2168}
2169
2170static void
2171update_known_hosts(struct hostkeys_update_ctx *ctx)
2172{
2173 int r, was_raw = 0;
2174 int loglevel = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK ?
2175 SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE;
2176 char *fp, *response;
2177 size_t i;
2178
2179 for (i = 0; i < ctx->nkeys; i++) {
2180 if (ctx->keys_seen[i] != 2)
2181 continue;
2182 if ((fp = sshkey_fingerprint(ctx->keys[i],
2183 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
2184 fatal("%s: sshkey_fingerprint failed", __func__);
2185 do_log2(loglevel, "Learned new hostkey: %s %s",
2186 sshkey_type(ctx->keys[i]), fp);
2187 free(fp);
2188 }
2189 for (i = 0; i < ctx->nold; i++) {
2190 if ((fp = sshkey_fingerprint(ctx->old_keys[i],
2191 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
2192 fatal("%s: sshkey_fingerprint failed", __func__);
2193 do_log2(loglevel, "Deprecating obsolete hostkey: %s %s",
2194 sshkey_type(ctx->old_keys[i]), fp);
2195 free(fp);
2196 }
2197 if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) {
2198 if (get_saved_tio() != NULL) {
2199 leave_raw_mode(1);
2200 was_raw = 1;
2201 }
2202 response = NULL;
2203 for (i = 0; !quit_pending && i < 3; i++) {
2204 free(response);
2205 response = read_passphrase("Accept updated hostkeys? "
2206 "(yes/no): ", RP_ECHO);
2207 if (strcasecmp(response, "yes") == 0)
2208 break;
2209 else if (quit_pending || response == NULL ||
2210 strcasecmp(response, "no") == 0) {
2211 options.update_hostkeys = 0;
2212 break;
2213 } else {
2214 do_log2(loglevel, "Please enter "
2215 "\"yes\" or \"no\"");
2216 }
2217 }
2218 if (quit_pending || i >= 3 || response == NULL)
2219 options.update_hostkeys = 0;
2220 free(response);
2221 if (was_raw)
2222 enter_raw_mode(1);
2223 }
2224
2225 /*
2226 * Now that all the keys are verified, we can go ahead and replace
2227 * them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't
2228 * cancel the operation).
2229 */
2230 if (options.update_hostkeys != 0 &&
2231 (r = hostfile_replace_entries(options.user_hostfiles[0],
2232 ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys,
2233 options.hash_known_hosts, 0,
2234 options.fingerprint_hash)) != 0)
2235 error("%s: hostfile_replace_entries failed: %s",
2236 __func__, ssh_err(r));
2074} 2237}
2238
2075static void 2239static void
2240client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx)
2241{
2242 struct ssh *ssh = active_state; /* XXX */
2243 struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
2244 size_t i, ndone;
2245 struct sshbuf *signdata;
2246 int r;
2247 const u_char *sig;
2248 size_t siglen;
2249
2250 if (ctx->nnew == 0)
2251 fatal("%s: ctx->nnew == 0", __func__); /* sanity */
2252 if (type != SSH2_MSG_REQUEST_SUCCESS) {
2253 error("Server failed to confirm ownership of "
2254 "private host keys");
2255 hostkeys_update_ctx_free(ctx);
2256 return;
2257 }
2258 if ((signdata = sshbuf_new()) == NULL)
2259 fatal("%s: sshbuf_new failed", __func__);
2260 /* Don't want to accidentally accept an unbound signature */
2261 if (ssh->kex->session_id_len == 0)
2262 fatal("%s: ssh->kex->session_id_len == 0", __func__);
2263 /*
2264 * Expect a signature for each of the ctx->nnew private keys we
2265 * haven't seen before. They will be in the same order as the
2266 * ctx->keys where the corresponding ctx->keys_seen[i] == 0.
2267 */
2268 for (ndone = i = 0; i < ctx->nkeys; i++) {
2269 if (ctx->keys_seen[i])
2270 continue;
2271 /* Prepare data to be signed: session ID, unique string, key */
2272 sshbuf_reset(signdata);
2273 if ( (r = sshbuf_put_cstring(signdata,
2274 "hostkeys-prove-00@openssh.com")) != 0 ||
2275 (r = sshbuf_put_string(signdata, ssh->kex->session_id,
2276 ssh->kex->session_id_len)) != 0 ||
2277 (r = sshkey_puts(ctx->keys[i], signdata)) != 0)
2278 fatal("%s: failed to prepare signature: %s",
2279 __func__, ssh_err(r));
2280 /* Extract and verify signature */
2281 if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) {
2282 error("%s: couldn't parse message: %s",
2283 __func__, ssh_err(r));
2284 goto out;
2285 }
2286 if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
2287 sshbuf_ptr(signdata), sshbuf_len(signdata), 0)) != 0) {
2288 error("%s: server gave bad signature for %s key %zu",
2289 __func__, sshkey_type(ctx->keys[i]), i);
2290 goto out;
2291 }
2292 /* Key is good. Mark it as 'seen' */
2293 ctx->keys_seen[i] = 2;
2294 ndone++;
2295 }
2296 if (ndone != ctx->nnew)
2297 fatal("%s: ndone != ctx->nnew (%zu / %zu)", __func__,
2298 ndone, ctx->nnew); /* Shouldn't happen */
2299 ssh_packet_check_eom(ssh);
2300
2301 /* Make the edits to known_hosts */
2302 update_known_hosts(ctx);
2303 out:
2304 hostkeys_update_ctx_free(ctx);
2305}
2306
2307/*
2308 * Handle hostkeys-00@openssh.com global request to inform the client of all
2309 * the server's hostkeys. The keys are checked against the user's
2310 * HostkeyAlgorithms preference before they are accepted.
2311 */
2312static int
2313client_input_hostkeys(void)
2314{
2315 struct ssh *ssh = active_state; /* XXX */
2316 const u_char *blob = NULL;
2317 size_t i, len = 0;
2318 struct sshbuf *buf = NULL;
2319 struct sshkey *key = NULL, **tmp;
2320 int r;
2321 char *fp;
2322 static int hostkeys_seen = 0; /* XXX use struct ssh */
2323 extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */
2324 struct hostkeys_update_ctx *ctx = NULL;
2325
2326 if (hostkeys_seen)
2327 fatal("%s: server already sent hostkeys", __func__);
2328 if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK &&
2329 options.batch_mode)
2330 return 1; /* won't ask in batchmode, so don't even try */
2331 if (!options.update_hostkeys || options.num_user_hostfiles <= 0)
2332 return 1;
2333
2334 ctx = xcalloc(1, sizeof(*ctx));
2335 while (ssh_packet_remaining(ssh) > 0) {
2336 sshkey_free(key);
2337 key = NULL;
2338 if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) {
2339 error("%s: couldn't parse message: %s",
2340 __func__, ssh_err(r));
2341 goto out;
2342 }
2343 if ((r = sshkey_from_blob(blob, len, &key)) != 0) {
2344 error("%s: parse key: %s", __func__, ssh_err(r));
2345 goto out;
2346 }
2347 fp = sshkey_fingerprint(key, options.fingerprint_hash,
2348 SSH_FP_DEFAULT);
2349 debug3("%s: received %s key %s", __func__,
2350 sshkey_type(key), fp);
2351 free(fp);
2352 /* Check that the key is accepted in HostkeyAlgorithms */
2353 if (options.hostkeyalgorithms != NULL &&
2354 match_pattern_list(sshkey_ssh_name(key),
2355 options.hostkeyalgorithms,
2356 strlen(options.hostkeyalgorithms), 0) != 1) {
2357 debug3("%s: %s key not permitted by HostkeyAlgorithms",
2358 __func__, sshkey_ssh_name(key));
2359 continue;
2360 }
2361 /* Skip certs */
2362 if (sshkey_is_cert(key)) {
2363 debug3("%s: %s key is a certificate; skipping",
2364 __func__, sshkey_ssh_name(key));
2365 continue;
2366 }
2367 /* Ensure keys are unique */
2368 for (i = 0; i < ctx->nkeys; i++) {
2369 if (sshkey_equal(key, ctx->keys[i])) {
2370 error("%s: received duplicated %s host key",
2371 __func__, sshkey_ssh_name(key));
2372 goto out;
2373 }
2374 }
2375 /* Key is good, record it */
2376 if ((tmp = reallocarray(ctx->keys, ctx->nkeys + 1,
2377 sizeof(*ctx->keys))) == NULL)
2378 fatal("%s: reallocarray failed nkeys = %zu",
2379 __func__, ctx->nkeys);
2380 ctx->keys = tmp;
2381 ctx->keys[ctx->nkeys++] = key;
2382 key = NULL;
2383 }
2384
2385 if (ctx->nkeys == 0) {
2386 debug("%s: server sent no hostkeys", __func__);
2387 goto out;
2388 }
2389
2390 if ((ctx->keys_seen = calloc(ctx->nkeys,
2391 sizeof(*ctx->keys_seen))) == NULL)
2392 fatal("%s: calloc failed", __func__);
2393
2394 get_hostfile_hostname_ipaddr(host,
2395 options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL,
2396 options.port, &ctx->host_str,
2397 options.check_host_ip ? &ctx->ip_str : NULL);
2398
2399 /* Find which keys we already know about. */
2400 if ((r = hostkeys_foreach(options.user_hostfiles[0], hostkeys_find,
2401 ctx, ctx->host_str, ctx->ip_str,
2402 HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) {
2403 error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
2404 goto out;
2405 }
2406
2407 /* Figure out if we have any new keys to add */
2408 ctx->nnew = 0;
2409 for (i = 0; i < ctx->nkeys; i++) {
2410 if (!ctx->keys_seen[i])
2411 ctx->nnew++;
2412 }
2413
2414 debug3("%s: %zu keys from server: %zu new, %zu retained. %zu to remove",
2415 __func__, ctx->nkeys, ctx->nnew, ctx->nkeys - ctx->nnew, ctx->nold);
2416
2417 if (ctx->nnew == 0 && ctx->nold != 0) {
2418 /* We have some keys to remove. Just do it. */
2419 update_known_hosts(ctx);
2420 } else if (ctx->nnew != 0) {
2421 /*
2422 * We have received hitherto-unseen keys from the server.
2423 * Ask the server to confirm ownership of the private halves.
2424 */
2425 debug3("%s: asking server to prove ownership for %zu keys",
2426 __func__, ctx->nnew);
2427 if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
2428 (r = sshpkt_put_cstring(ssh,
2429 "hostkeys-prove-00@openssh.com")) != 0 ||
2430 (r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */
2431 fatal("%s: cannot prepare packet: %s",
2432 __func__, ssh_err(r));
2433 if ((buf = sshbuf_new()) == NULL)
2434 fatal("%s: sshbuf_new", __func__);
2435 for (i = 0; i < ctx->nkeys; i++) {
2436 if (ctx->keys_seen[i])
2437 continue;
2438 sshbuf_reset(buf);
2439 if ((r = sshkey_putb(ctx->keys[i], buf)) != 0)
2440 fatal("%s: sshkey_putb: %s",
2441 __func__, ssh_err(r));
2442 if ((r = sshpkt_put_stringb(ssh, buf)) != 0)
2443 fatal("%s: sshpkt_put_string: %s",
2444 __func__, ssh_err(r));
2445 }
2446 if ((r = sshpkt_send(ssh)) != 0)
2447 fatal("%s: sshpkt_send: %s", __func__, ssh_err(r));
2448 client_register_global_confirm(
2449 client_global_hostkeys_private_confirm, ctx);
2450 ctx = NULL; /* will be freed in callback */
2451 }
2452
2453 /* Success */
2454 out:
2455 hostkeys_update_ctx_free(ctx);
2456 sshkey_free(key);
2457 sshbuf_free(buf);
2458 /*
2459 * NB. Return success for all cases. The server doesn't need to know
2460 * what the client does with its hosts file.
2461 */
2462 return 1;
2463}
2464
2465static int
2076client_input_global_request(int type, u_int32_t seq, void *ctxt) 2466client_input_global_request(int type, u_int32_t seq, void *ctxt)
2077{ 2467{
2078 char *rtype; 2468 char *rtype;
2079 int want_reply; 2469 int want_reply;
2080 int success = 0; 2470 int success = 0;
2081 2471
2082 rtype = packet_get_string(NULL); 2472 rtype = packet_get_cstring(NULL);
2083 want_reply = packet_get_char(); 2473 want_reply = packet_get_char();
2084 debug("client_input_global_request: rtype %s want_reply %d", 2474 debug("client_input_global_request: rtype %s want_reply %d",
2085 rtype, want_reply); 2475 rtype, want_reply);
2476 if (strcmp(rtype, "hostkeys-00@openssh.com") == 0)
2477 success = client_input_hostkeys();
2086 if (want_reply) { 2478 if (want_reply) {
2087 packet_start(success ? 2479 packet_start(success ?
2088 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 2480 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
@@ -2090,6 +2482,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
2090 packet_write_wait(); 2482 packet_write_wait();
2091 } 2483 }
2092 free(rtype); 2484 free(rtype);
2485 return 0;
2093} 2486}
2094 2487
2095void 2488void