summaryrefslogtreecommitdiff
path: root/clientloop.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2015-08-19 14:23:51 +0100
committerColin Watson <cjwatson@debian.org>2015-08-19 16:48:11 +0100
commit0f0841b2d28b7463267d4d91577e72e3340a1d3a (patch)
treeba55fcd2b6e2cc22b30f5afb561dbb3da4c8b6c7 /clientloop.c
parentf2a5f5dae656759efb0b76c3d94890b65c197a02 (diff)
parent8698446b972003b63dfe5dcbdb86acfe986afb85 (diff)
New upstream release (6.8p1).
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 0180774bb..45cef8829 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#ifdef GSSAPI 117#ifdef GSSAPI
115#include "ssh-gss.h" 118#include "ssh-gss.h"
@@ -195,9 +198,6 @@ TAILQ_HEAD(global_confirms, global_confirm);
195static struct global_confirms global_confirms = 198static struct global_confirms global_confirms =
196 TAILQ_HEAD_INITIALIZER(global_confirms); 199 TAILQ_HEAD_INITIALIZER(global_confirms);
197 200
198/*XXX*/
199extern Kex *xxx_kex;
200
201void ssh_process_session2_setup(int, int, int, Buffer *); 201void ssh_process_session2_setup(int, int, int, Buffer *);
202 202
203/* Restores stdin to blocking mode. */ 203/* Restores stdin to blocking mode. */
@@ -345,12 +345,12 @@ client_x11_get_proto(const char *display, const char *xauth_path,
345 display = xdisplay; 345 display = xdisplay;
346 } 346 }
347 if (trusted == 0) { 347 if (trusted == 0) {
348 xauthdir = xmalloc(MAXPATHLEN); 348 xauthdir = xmalloc(PATH_MAX);
349 xauthfile = xmalloc(MAXPATHLEN); 349 xauthfile = xmalloc(PATH_MAX);
350 mktemp_proto(xauthdir, MAXPATHLEN); 350 mktemp_proto(xauthdir, PATH_MAX);
351 if (mkdtemp(xauthdir) != NULL) { 351 if (mkdtemp(xauthdir) != NULL) {
352 do_unlink = 1; 352 do_unlink = 1;
353 snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", 353 snprintf(xauthfile, PATH_MAX, "%s/xauthfile",
354 xauthdir); 354 xauthdir);
355 snprintf(cmd, sizeof(cmd), 355 snprintf(cmd, sizeof(cmd),
356 "%s -f %s generate %s " SSH_X11_PROTO 356 "%s -f %s generate %s " SSH_X11_PROTO
@@ -542,13 +542,13 @@ client_check_window_change(void)
542 } 542 }
543} 543}
544 544
545static void 545static int
546client_global_request_reply(int type, u_int32_t seq, void *ctxt) 546client_global_request_reply(int type, u_int32_t seq, void *ctxt)
547{ 547{
548 struct global_confirm *gc; 548 struct global_confirm *gc;
549 549
550 if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) 550 if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
551 return; 551 return 0;
552 if (gc->cb != NULL) 552 if (gc->cb != NULL)
553 gc->cb(type, seq, gc->ctx); 553 gc->cb(type, seq, gc->ctx);
554 if (--gc->ref_count <= 0) { 554 if (--gc->ref_count <= 0) {
@@ -558,6 +558,7 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt)
558 } 558 }
559 559
560 packet_set_alive_timeouts(0); 560 packet_set_alive_timeouts(0);
561 return 0;
561} 562}
562 563
563static void 564static void
@@ -1423,8 +1424,7 @@ client_process_output(fd_set *writeset)
1423static void 1424static void
1424client_process_buffered_input_packets(void) 1425client_process_buffered_input_packets(void)
1425{ 1426{
1426 dispatch_run(DISPATCH_NONBLOCK, &quit_pending, 1427 dispatch_run(DISPATCH_NONBLOCK, &quit_pending, active_state);
1427 compat20 ? xxx_kex : NULL);
1428} 1428}
1429 1429
1430/* scan buf[] for '~' before sending data to the peer */ 1430/* scan buf[] for '~' before sending data to the peer */
@@ -1478,7 +1478,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1478{ 1478{
1479 fd_set *readset = NULL, *writeset = NULL; 1479 fd_set *readset = NULL, *writeset = NULL;
1480 double start_time, total_time; 1480 double start_time, total_time;
1481 int max_fd = 0, max_fd2 = 0, len, rekeying = 0; 1481 int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0;
1482 u_int64_t ibytes, obytes; 1482 u_int64_t ibytes, obytes;
1483 u_int nalloc = 0; 1483 u_int nalloc = 0;
1484 char buf[100]; 1484 char buf[100];
@@ -1563,7 +1563,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1563 if (compat20 && session_closed && !channel_still_open()) 1563 if (compat20 && session_closed && !channel_still_open())
1564 break; 1564 break;
1565 1565
1566 rekeying = (xxx_kex != NULL && !xxx_kex->done); 1566 rekeying = (active_state->kex != NULL && !active_state->kex->done);
1567 1567
1568 if (rekeying) { 1568 if (rekeying) {
1569 debug("rekeying in progress"); 1569 debug("rekeying in progress");
@@ -1616,8 +1616,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1616 1616
1617 if (need_rekeying || packet_need_rekeying()) { 1617 if (need_rekeying || packet_need_rekeying()) {
1618 debug("need rekeying"); 1618 debug("need rekeying");
1619 xxx_kex->done = 0; 1619 active_state->kex->done = 0;
1620 kex_send_kexinit(xxx_kex); 1620 if ((r = kex_send_kexinit(active_state)) != 0)
1621 fatal("%s: kex_send_kexinit: %s",
1622 __func__, ssh_err(r));
1621 need_rekeying = 0; 1623 need_rekeying = 0;
1622 } 1624 }
1623 } 1625 }
@@ -1748,8 +1750,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1748 1750
1749 /* Report bytes transferred, and transfer rates. */ 1751 /* Report bytes transferred, and transfer rates. */
1750 total_time = get_current_time() - start_time; 1752 total_time = get_current_time() - start_time;
1751 packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); 1753 packet_get_bytes(&ibytes, &obytes);
1752 packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
1753 verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds", 1754 verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
1754 (unsigned long long)obytes, (unsigned long long)ibytes, total_time); 1755 (unsigned long long)obytes, (unsigned long long)ibytes, total_time);
1755 if (total_time > 0) 1756 if (total_time > 0)
@@ -1762,7 +1763,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1762 1763
1763/*********/ 1764/*********/
1764 1765
1765static void 1766static int
1766client_input_stdout_data(int type, u_int32_t seq, void *ctxt) 1767client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
1767{ 1768{
1768 u_int data_len; 1769 u_int data_len;
@@ -1771,8 +1772,9 @@ client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
1771 buffer_append(&stdout_buffer, data, data_len); 1772 buffer_append(&stdout_buffer, data, data_len);
1772 explicit_bzero(data, data_len); 1773 explicit_bzero(data, data_len);
1773 free(data); 1774 free(data);
1775 return 0;
1774} 1776}
1775static void 1777static int
1776client_input_stderr_data(int type, u_int32_t seq, void *ctxt) 1778client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
1777{ 1779{
1778 u_int data_len; 1780 u_int data_len;
@@ -1781,8 +1783,9 @@ client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
1781 buffer_append(&stderr_buffer, data, data_len); 1783 buffer_append(&stderr_buffer, data, data_len);
1782 explicit_bzero(data, data_len); 1784 explicit_bzero(data, data_len);
1783 free(data); 1785 free(data);
1786 return 0;
1784} 1787}
1785static void 1788static int
1786client_input_exit_status(int type, u_int32_t seq, void *ctxt) 1789client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1787{ 1790{
1788 exit_status = packet_get_int(); 1791 exit_status = packet_get_int();
@@ -1797,12 +1800,14 @@ client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1797 packet_write_wait(); 1800 packet_write_wait();
1798 /* Flag that we want to exit. */ 1801 /* Flag that we want to exit. */
1799 quit_pending = 1; 1802 quit_pending = 1;
1803 return 0;
1800} 1804}
1801static void 1805
1806static int
1802client_input_agent_open(int type, u_int32_t seq, void *ctxt) 1807client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1803{ 1808{
1804 Channel *c = NULL; 1809 Channel *c = NULL;
1805 int remote_id, sock; 1810 int r, remote_id, sock;
1806 1811
1807 /* Read the remote channel number from the message. */ 1812 /* Read the remote channel number from the message. */
1808 remote_id = packet_get_int(); 1813 remote_id = packet_get_int();
@@ -1812,7 +1817,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1812 * Get a connection to the local authentication agent (this may again 1817 * Get a connection to the local authentication agent (this may again
1813 * get forwarded). 1818 * get forwarded).
1814 */ 1819 */
1815 sock = ssh_get_authentication_socket(); 1820 if ((r = ssh_get_authentication_socket(&sock)) != 0 &&
1821 r != SSH_ERR_AGENT_NOT_PRESENT)
1822 debug("%s: ssh_get_authentication_socket: %s",
1823 __func__, ssh_err(r));
1824
1816 1825
1817 /* 1826 /*
1818 * If we could not connect the agent, send an error message back to 1827 * If we could not connect the agent, send an error message back to
@@ -1837,6 +1846,7 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1837 packet_put_int(c->self); 1846 packet_put_int(c->self);
1838 } 1847 }
1839 packet_send(); 1848 packet_send();
1849 return 0;
1840} 1850}
1841 1851
1842static Channel * 1852static Channel *
@@ -1930,7 +1940,7 @@ static Channel *
1930client_request_agent(const char *request_type, int rchan) 1940client_request_agent(const char *request_type, int rchan)
1931{ 1941{
1932 Channel *c = NULL; 1942 Channel *c = NULL;
1933 int sock; 1943 int r, sock;
1934 1944
1935 if (!options.forward_agent) { 1945 if (!options.forward_agent) {
1936 error("Warning: ssh server tried agent forwarding."); 1946 error("Warning: ssh server tried agent forwarding.");
@@ -1938,9 +1948,12 @@ client_request_agent(const char *request_type, int rchan)
1938 "malicious server."); 1948 "malicious server.");
1939 return NULL; 1949 return NULL;
1940 } 1950 }
1941 sock = ssh_get_authentication_socket(); 1951 if ((r = ssh_get_authentication_socket(&sock)) != 0) {
1942 if (sock < 0) 1952 if (r != SSH_ERR_AGENT_NOT_PRESENT)
1953 debug("%s: ssh_get_authentication_socket: %s",
1954 __func__, ssh_err(r));
1943 return NULL; 1955 return NULL;
1956 }
1944 c = channel_new("authentication agent connection", 1957 c = channel_new("authentication agent connection",
1945 SSH_CHANNEL_OPEN, sock, sock, -1, 1958 SSH_CHANNEL_OPEN, sock, sock, -1,
1946 CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, 1959 CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
@@ -1994,7 +2007,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
1994} 2007}
1995 2008
1996/* XXXX move to generic input handler */ 2009/* XXXX move to generic input handler */
1997static void 2010static int
1998client_input_channel_open(int type, u_int32_t seq, void *ctxt) 2011client_input_channel_open(int type, u_int32_t seq, void *ctxt)
1999{ 2012{
2000 Channel *c = NULL; 2013 Channel *c = NULL;
@@ -2045,8 +2058,10 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
2045 packet_send(); 2058 packet_send();
2046 } 2059 }
2047 free(ctype); 2060 free(ctype);
2061 return 0;
2048} 2062}
2049static void 2063
2064static int
2050client_input_channel_req(int type, u_int32_t seq, void *ctxt) 2065client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2051{ 2066{
2052 Channel *c = NULL; 2067 Channel *c = NULL;
@@ -2091,18 +2106,395 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2091 packet_send(); 2106 packet_send();
2092 } 2107 }
2093 free(rtype); 2108 free(rtype);
2109 return 0;
2110}
2111
2112struct hostkeys_update_ctx {
2113 /* The hostname and (optionally) IP address string for the server */
2114 char *host_str, *ip_str;
2115
2116 /*
2117 * Keys received from the server and a flag for each indicating
2118 * whether they already exist in known_hosts.
2119 * keys_seen is filled in by hostkeys_find() and later (for new
2120 * keys) by client_global_hostkeys_private_confirm().
2121 */
2122 struct sshkey **keys;
2123 int *keys_seen;
2124 size_t nkeys;
2125
2126 size_t nnew;
2127
2128 /*
2129 * Keys that are in known_hosts, but were not present in the update
2130 * from the server (i.e. scheduled to be deleted).
2131 * Filled in by hostkeys_find().
2132 */
2133 struct sshkey **old_keys;
2134 size_t nold;
2135};
2136
2137static void
2138hostkeys_update_ctx_free(struct hostkeys_update_ctx *ctx)
2139{
2140 size_t i;
2141
2142 if (ctx == NULL)
2143 return;
2144 for (i = 0; i < ctx->nkeys; i++)
2145 sshkey_free(ctx->keys[i]);
2146 free(ctx->keys);
2147 free(ctx->keys_seen);
2148 for (i = 0; i < ctx->nold; i++)
2149 sshkey_free(ctx->old_keys[i]);
2150 free(ctx->old_keys);
2151 free(ctx->host_str);
2152 free(ctx->ip_str);
2153 free(ctx);
2154}
2155
2156static int
2157hostkeys_find(struct hostkey_foreach_line *l, void *_ctx)
2158{
2159 struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
2160 size_t i;
2161 struct sshkey **tmp;
2162
2163 if (l->status != HKF_STATUS_MATCHED || l->key == NULL ||
2164 l->key->type == KEY_RSA1)
2165 return 0;
2166
2167 /* Mark off keys we've already seen for this host */
2168 for (i = 0; i < ctx->nkeys; i++) {
2169 if (sshkey_equal(l->key, ctx->keys[i])) {
2170 debug3("%s: found %s key at %s:%ld", __func__,
2171 sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum);
2172 ctx->keys_seen[i] = 1;
2173 return 0;
2174 }
2175 }
2176 /* This line contained a key that not offered by the server */
2177 debug3("%s: deprecated %s key at %s:%ld", __func__,
2178 sshkey_ssh_name(l->key), l->path, l->linenum);
2179 if ((tmp = reallocarray(ctx->old_keys, ctx->nold + 1,
2180 sizeof(*ctx->old_keys))) == NULL)
2181 fatal("%s: reallocarray failed nold = %zu",
2182 __func__, ctx->nold);
2183 ctx->old_keys = tmp;
2184 ctx->old_keys[ctx->nold++] = l->key;
2185 l->key = NULL;
2186
2187 return 0;
2188}
2189
2190static void
2191update_known_hosts(struct hostkeys_update_ctx *ctx)
2192{
2193 int r, was_raw = 0;
2194 int loglevel = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK ?
2195 SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE;
2196 char *fp, *response;
2197 size_t i;
2198
2199 for (i = 0; i < ctx->nkeys; i++) {
2200 if (ctx->keys_seen[i] != 2)
2201 continue;
2202 if ((fp = sshkey_fingerprint(ctx->keys[i],
2203 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
2204 fatal("%s: sshkey_fingerprint failed", __func__);
2205 do_log2(loglevel, "Learned new hostkey: %s %s",
2206 sshkey_type(ctx->keys[i]), fp);
2207 free(fp);
2208 }
2209 for (i = 0; i < ctx->nold; i++) {
2210 if ((fp = sshkey_fingerprint(ctx->old_keys[i],
2211 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
2212 fatal("%s: sshkey_fingerprint failed", __func__);
2213 do_log2(loglevel, "Deprecating obsolete hostkey: %s %s",
2214 sshkey_type(ctx->old_keys[i]), fp);
2215 free(fp);
2216 }
2217 if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) {
2218 if (get_saved_tio() != NULL) {
2219 leave_raw_mode(1);
2220 was_raw = 1;
2221 }
2222 response = NULL;
2223 for (i = 0; !quit_pending && i < 3; i++) {
2224 free(response);
2225 response = read_passphrase("Accept updated hostkeys? "
2226 "(yes/no): ", RP_ECHO);
2227 if (strcasecmp(response, "yes") == 0)
2228 break;
2229 else if (quit_pending || response == NULL ||
2230 strcasecmp(response, "no") == 0) {
2231 options.update_hostkeys = 0;
2232 break;
2233 } else {
2234 do_log2(loglevel, "Please enter "
2235 "\"yes\" or \"no\"");
2236 }
2237 }
2238 if (quit_pending || i >= 3 || response == NULL)
2239 options.update_hostkeys = 0;
2240 free(response);
2241 if (was_raw)
2242 enter_raw_mode(1);
2243 }
2244
2245 /*
2246 * Now that all the keys are verified, we can go ahead and replace
2247 * them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't
2248 * cancel the operation).
2249 */
2250 if (options.update_hostkeys != 0 &&
2251 (r = hostfile_replace_entries(options.user_hostfiles[0],
2252 ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys,
2253 options.hash_known_hosts, 0,
2254 options.fingerprint_hash)) != 0)
2255 error("%s: hostfile_replace_entries failed: %s",
2256 __func__, ssh_err(r));
2094} 2257}
2258
2095static void 2259static void
2260client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx)
2261{
2262 struct ssh *ssh = active_state; /* XXX */
2263 struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
2264 size_t i, ndone;
2265 struct sshbuf *signdata;
2266 int r;
2267 const u_char *sig;
2268 size_t siglen;
2269
2270 if (ctx->nnew == 0)
2271 fatal("%s: ctx->nnew == 0", __func__); /* sanity */
2272 if (type != SSH2_MSG_REQUEST_SUCCESS) {
2273 error("Server failed to confirm ownership of "
2274 "private host keys");
2275 hostkeys_update_ctx_free(ctx);
2276 return;
2277 }
2278 if ((signdata = sshbuf_new()) == NULL)
2279 fatal("%s: sshbuf_new failed", __func__);
2280 /* Don't want to accidentally accept an unbound signature */
2281 if (ssh->kex->session_id_len == 0)
2282 fatal("%s: ssh->kex->session_id_len == 0", __func__);
2283 /*
2284 * Expect a signature for each of the ctx->nnew private keys we
2285 * haven't seen before. They will be in the same order as the
2286 * ctx->keys where the corresponding ctx->keys_seen[i] == 0.
2287 */
2288 for (ndone = i = 0; i < ctx->nkeys; i++) {
2289 if (ctx->keys_seen[i])
2290 continue;
2291 /* Prepare data to be signed: session ID, unique string, key */
2292 sshbuf_reset(signdata);
2293 if ( (r = sshbuf_put_cstring(signdata,
2294 "hostkeys-prove-00@openssh.com")) != 0 ||
2295 (r = sshbuf_put_string(signdata, ssh->kex->session_id,
2296 ssh->kex->session_id_len)) != 0 ||
2297 (r = sshkey_puts(ctx->keys[i], signdata)) != 0)
2298 fatal("%s: failed to prepare signature: %s",
2299 __func__, ssh_err(r));
2300 /* Extract and verify signature */
2301 if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) {
2302 error("%s: couldn't parse message: %s",
2303 __func__, ssh_err(r));
2304 goto out;
2305 }
2306 if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
2307 sshbuf_ptr(signdata), sshbuf_len(signdata), 0)) != 0) {
2308 error("%s: server gave bad signature for %s key %zu",
2309 __func__, sshkey_type(ctx->keys[i]), i);
2310 goto out;
2311 }
2312 /* Key is good. Mark it as 'seen' */
2313 ctx->keys_seen[i] = 2;
2314 ndone++;
2315 }
2316 if (ndone != ctx->nnew)
2317 fatal("%s: ndone != ctx->nnew (%zu / %zu)", __func__,
2318 ndone, ctx->nnew); /* Shouldn't happen */
2319 ssh_packet_check_eom(ssh);
2320
2321 /* Make the edits to known_hosts */
2322 update_known_hosts(ctx);
2323 out:
2324 hostkeys_update_ctx_free(ctx);
2325}
2326
2327/*
2328 * Handle hostkeys-00@openssh.com global request to inform the client of all
2329 * the server's hostkeys. The keys are checked against the user's
2330 * HostkeyAlgorithms preference before they are accepted.
2331 */
2332static int
2333client_input_hostkeys(void)
2334{
2335 struct ssh *ssh = active_state; /* XXX */
2336 const u_char *blob = NULL;
2337 size_t i, len = 0;
2338 struct sshbuf *buf = NULL;
2339 struct sshkey *key = NULL, **tmp;
2340 int r;
2341 char *fp;
2342 static int hostkeys_seen = 0; /* XXX use struct ssh */
2343 extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */
2344 struct hostkeys_update_ctx *ctx = NULL;
2345
2346 if (hostkeys_seen)
2347 fatal("%s: server already sent hostkeys", __func__);
2348 if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK &&
2349 options.batch_mode)
2350 return 1; /* won't ask in batchmode, so don't even try */
2351 if (!options.update_hostkeys || options.num_user_hostfiles <= 0)
2352 return 1;
2353
2354 ctx = xcalloc(1, sizeof(*ctx));
2355 while (ssh_packet_remaining(ssh) > 0) {
2356 sshkey_free(key);
2357 key = NULL;
2358 if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) {
2359 error("%s: couldn't parse message: %s",
2360 __func__, ssh_err(r));
2361 goto out;
2362 }
2363 if ((r = sshkey_from_blob(blob, len, &key)) != 0) {
2364 error("%s: parse key: %s", __func__, ssh_err(r));
2365 goto out;
2366 }
2367 fp = sshkey_fingerprint(key, options.fingerprint_hash,
2368 SSH_FP_DEFAULT);
2369 debug3("%s: received %s key %s", __func__,
2370 sshkey_type(key), fp);
2371 free(fp);
2372 /* Check that the key is accepted in HostkeyAlgorithms */
2373 if (options.hostkeyalgorithms != NULL &&
2374 match_pattern_list(sshkey_ssh_name(key),
2375 options.hostkeyalgorithms,
2376 strlen(options.hostkeyalgorithms), 0) != 1) {
2377 debug3("%s: %s key not permitted by HostkeyAlgorithms",
2378 __func__, sshkey_ssh_name(key));
2379 continue;
2380 }
2381 /* Skip certs */
2382 if (sshkey_is_cert(key)) {
2383 debug3("%s: %s key is a certificate; skipping",
2384 __func__, sshkey_ssh_name(key));
2385 continue;
2386 }
2387 /* Ensure keys are unique */
2388 for (i = 0; i < ctx->nkeys; i++) {
2389 if (sshkey_equal(key, ctx->keys[i])) {
2390 error("%s: received duplicated %s host key",
2391 __func__, sshkey_ssh_name(key));
2392 goto out;
2393 }
2394 }
2395 /* Key is good, record it */
2396 if ((tmp = reallocarray(ctx->keys, ctx->nkeys + 1,
2397 sizeof(*ctx->keys))) == NULL)
2398 fatal("%s: reallocarray failed nkeys = %zu",
2399 __func__, ctx->nkeys);
2400 ctx->keys = tmp;
2401 ctx->keys[ctx->nkeys++] = key;
2402 key = NULL;
2403 }
2404
2405 if (ctx->nkeys == 0) {
2406 debug("%s: server sent no hostkeys", __func__);
2407 goto out;
2408 }
2409
2410 if ((ctx->keys_seen = calloc(ctx->nkeys,
2411 sizeof(*ctx->keys_seen))) == NULL)
2412 fatal("%s: calloc failed", __func__);
2413
2414 get_hostfile_hostname_ipaddr(host,
2415 options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL,
2416 options.port, &ctx->host_str,
2417 options.check_host_ip ? &ctx->ip_str : NULL);
2418
2419 /* Find which keys we already know about. */
2420 if ((r = hostkeys_foreach(options.user_hostfiles[0], hostkeys_find,
2421 ctx, ctx->host_str, ctx->ip_str,
2422 HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) {
2423 error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
2424 goto out;
2425 }
2426
2427 /* Figure out if we have any new keys to add */
2428 ctx->nnew = 0;
2429 for (i = 0; i < ctx->nkeys; i++) {
2430 if (!ctx->keys_seen[i])
2431 ctx->nnew++;
2432 }
2433
2434 debug3("%s: %zu keys from server: %zu new, %zu retained. %zu to remove",
2435 __func__, ctx->nkeys, ctx->nnew, ctx->nkeys - ctx->nnew, ctx->nold);
2436
2437 if (ctx->nnew == 0 && ctx->nold != 0) {
2438 /* We have some keys to remove. Just do it. */
2439 update_known_hosts(ctx);
2440 } else if (ctx->nnew != 0) {
2441 /*
2442 * We have received hitherto-unseen keys from the server.
2443 * Ask the server to confirm ownership of the private halves.
2444 */
2445 debug3("%s: asking server to prove ownership for %zu keys",
2446 __func__, ctx->nnew);
2447 if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
2448 (r = sshpkt_put_cstring(ssh,
2449 "hostkeys-prove-00@openssh.com")) != 0 ||
2450 (r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */
2451 fatal("%s: cannot prepare packet: %s",
2452 __func__, ssh_err(r));
2453 if ((buf = sshbuf_new()) == NULL)
2454 fatal("%s: sshbuf_new", __func__);
2455 for (i = 0; i < ctx->nkeys; i++) {
2456 if (ctx->keys_seen[i])
2457 continue;
2458 sshbuf_reset(buf);
2459 if ((r = sshkey_putb(ctx->keys[i], buf)) != 0)
2460 fatal("%s: sshkey_putb: %s",
2461 __func__, ssh_err(r));
2462 if ((r = sshpkt_put_stringb(ssh, buf)) != 0)
2463 fatal("%s: sshpkt_put_string: %s",
2464 __func__, ssh_err(r));
2465 }
2466 if ((r = sshpkt_send(ssh)) != 0)
2467 fatal("%s: sshpkt_send: %s", __func__, ssh_err(r));
2468 client_register_global_confirm(
2469 client_global_hostkeys_private_confirm, ctx);
2470 ctx = NULL; /* will be freed in callback */
2471 }
2472
2473 /* Success */
2474 out:
2475 hostkeys_update_ctx_free(ctx);
2476 sshkey_free(key);
2477 sshbuf_free(buf);
2478 /*
2479 * NB. Return success for all cases. The server doesn't need to know
2480 * what the client does with its hosts file.
2481 */
2482 return 1;
2483}
2484
2485static int
2096client_input_global_request(int type, u_int32_t seq, void *ctxt) 2486client_input_global_request(int type, u_int32_t seq, void *ctxt)
2097{ 2487{
2098 char *rtype; 2488 char *rtype;
2099 int want_reply; 2489 int want_reply;
2100 int success = 0; 2490 int success = 0;
2101 2491
2102 rtype = packet_get_string(NULL); 2492 rtype = packet_get_cstring(NULL);
2103 want_reply = packet_get_char(); 2493 want_reply = packet_get_char();
2104 debug("client_input_global_request: rtype %s want_reply %d", 2494 debug("client_input_global_request: rtype %s want_reply %d",
2105 rtype, want_reply); 2495 rtype, want_reply);
2496 if (strcmp(rtype, "hostkeys-00@openssh.com") == 0)
2497 success = client_input_hostkeys();
2106 if (want_reply) { 2498 if (want_reply) {
2107 packet_start(success ? 2499 packet_start(success ?
2108 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 2500 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
@@ -2110,6 +2502,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
2110 packet_write_wait(); 2502 packet_write_wait();
2111 } 2503 }
2112 free(rtype); 2504 free(rtype);
2505 return 0;
2113} 2506}
2114 2507
2115void 2508void