diff options
author | Colin Watson <cjwatson@debian.org> | 2020-02-21 11:57:14 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2020-02-21 14:27:02 +0000 |
commit | 886e47e745586c34e81cfd5c5fb9b5dbc8e84d04 (patch) | |
tree | dd6c3b4dc64a17c520af7aaf213163f8a0a63e56 /clientloop.c | |
parent | ac2b4c0697fcac554041ab95f81736887eadf6ec (diff) | |
parent | a2dabf35ce0228c86a288d11cc847a9d9801604f (diff) |
New upstream release (8.2p1)
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 137 |
1 files changed, 99 insertions, 38 deletions
diff --git a/clientloop.c b/clientloop.c index 9def2a1a9..1bdac6a46 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.327 2019/07/24 08:57:00 mestre Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.340 2020/02/02 09:45:34 dtucker 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 |
@@ -77,10 +77,10 @@ | |||
77 | #include <paths.h> | 77 | #include <paths.h> |
78 | #endif | 78 | #endif |
79 | #include <signal.h> | 79 | #include <signal.h> |
80 | #include <stdarg.h> | ||
81 | #include <stdio.h> | 80 | #include <stdio.h> |
82 | #include <stdlib.h> | 81 | #include <stdlib.h> |
83 | #include <string.h> | 82 | #include <string.h> |
83 | #include <stdarg.h> | ||
84 | #include <termios.h> | 84 | #include <termios.h> |
85 | #include <pwd.h> | 85 | #include <pwd.h> |
86 | #include <unistd.h> | 86 | #include <unistd.h> |
@@ -139,6 +139,12 @@ extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ | |||
139 | extern char *host; | 139 | extern char *host; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * If this field is not NULL, the ForwardAgent socket is this path and different | ||
143 | * instead of SSH_AUTH_SOCK. | ||
144 | */ | ||
145 | extern char *forward_agent_sock_path; | ||
146 | |||
147 | /* | ||
142 | * Flag to indicate that we have received a window change signal which has | 148 | * Flag to indicate that we have received a window change signal which has |
143 | * not yet been processed. This will cause a message indicating the new | 149 | * not yet been processed. This will cause a message indicating the new |
144 | * window size to be sent to the server a little later. This is volatile | 150 | * window size to be sent to the server a little later. This is volatile |
@@ -783,7 +789,7 @@ process_cmdline(struct ssh *ssh) | |||
783 | memset(&fwd, 0, sizeof(fwd)); | 789 | memset(&fwd, 0, sizeof(fwd)); |
784 | 790 | ||
785 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 791 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
786 | handler = signal(SIGINT, SIG_IGN); | 792 | handler = ssh_signal(SIGINT, SIG_IGN); |
787 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); | 793 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); |
788 | if (s == NULL) | 794 | if (s == NULL) |
789 | goto out; | 795 | goto out; |
@@ -881,7 +887,7 @@ process_cmdline(struct ssh *ssh) | |||
881 | } | 887 | } |
882 | 888 | ||
883 | out: | 889 | out: |
884 | signal(SIGINT, handler); | 890 | ssh_signal(SIGINT, handler); |
885 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 891 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
886 | free(cmd); | 892 | free(cmd); |
887 | free(fwd.listen_host); | 893 | free(fwd.listen_host); |
@@ -1304,15 +1310,15 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, | |||
1304 | * Set signal handlers, (e.g. to restore non-blocking mode) | 1310 | * Set signal handlers, (e.g. to restore non-blocking mode) |
1305 | * but don't overwrite SIG_IGN, matches behaviour from rsh(1) | 1311 | * but don't overwrite SIG_IGN, matches behaviour from rsh(1) |
1306 | */ | 1312 | */ |
1307 | if (signal(SIGHUP, SIG_IGN) != SIG_IGN) | 1313 | if (ssh_signal(SIGHUP, SIG_IGN) != SIG_IGN) |
1308 | signal(SIGHUP, signal_handler); | 1314 | ssh_signal(SIGHUP, signal_handler); |
1309 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | 1315 | if (ssh_signal(SIGINT, SIG_IGN) != SIG_IGN) |
1310 | signal(SIGINT, signal_handler); | 1316 | ssh_signal(SIGINT, signal_handler); |
1311 | if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) | 1317 | if (ssh_signal(SIGQUIT, SIG_IGN) != SIG_IGN) |
1312 | signal(SIGQUIT, signal_handler); | 1318 | ssh_signal(SIGQUIT, signal_handler); |
1313 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) | 1319 | if (ssh_signal(SIGTERM, SIG_IGN) != SIG_IGN) |
1314 | signal(SIGTERM, signal_handler); | 1320 | ssh_signal(SIGTERM, signal_handler); |
1315 | signal(SIGWINCH, window_change_handler); | 1321 | ssh_signal(SIGWINCH, window_change_handler); |
1316 | 1322 | ||
1317 | if (have_pty) | 1323 | if (have_pty) |
1318 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1324 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
@@ -1399,8 +1405,12 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, | |||
1399 | * Send as much buffered packet data as possible to the | 1405 | * Send as much buffered packet data as possible to the |
1400 | * sender. | 1406 | * sender. |
1401 | */ | 1407 | */ |
1402 | if (FD_ISSET(connection_out, writeset)) | 1408 | if (FD_ISSET(connection_out, writeset)) { |
1403 | ssh_packet_write_poll(ssh); | 1409 | if ((r = ssh_packet_write_poll(ssh)) != 0) { |
1410 | sshpkt_fatal(ssh, r, | ||
1411 | "%s: ssh_packet_write_poll", __func__); | ||
1412 | } | ||
1413 | } | ||
1404 | 1414 | ||
1405 | /* | 1415 | /* |
1406 | * If we are a backgrounded control master, and the | 1416 | * If we are a backgrounded control master, and the |
@@ -1420,7 +1430,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, | |||
1420 | /* Terminate the session. */ | 1430 | /* Terminate the session. */ |
1421 | 1431 | ||
1422 | /* Stop watching for window change. */ | 1432 | /* Stop watching for window change. */ |
1423 | signal(SIGWINCH, SIG_DFL); | 1433 | ssh_signal(SIGWINCH, SIG_DFL); |
1424 | 1434 | ||
1425 | if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || | 1435 | if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || |
1426 | (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_BY_APPLICATION)) != 0 || | 1436 | (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_BY_APPLICATION)) != 0 || |
@@ -1631,7 +1641,12 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan) | |||
1631 | "malicious server."); | 1641 | "malicious server."); |
1632 | return NULL; | 1642 | return NULL; |
1633 | } | 1643 | } |
1634 | if ((r = ssh_get_authentication_socket(&sock)) != 0) { | 1644 | if (forward_agent_sock_path == NULL) { |
1645 | r = ssh_get_authentication_socket(&sock); | ||
1646 | } else { | ||
1647 | r = ssh_get_authentication_socket_path(forward_agent_sock_path, &sock); | ||
1648 | } | ||
1649 | if (r != 0) { | ||
1635 | if (r != SSH_ERR_AGENT_NOT_PRESENT) | 1650 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
1636 | debug("%s: ssh_get_authentication_socket: %s", | 1651 | debug("%s: ssh_get_authentication_socket: %s", |
1637 | __func__, ssh_err(r)); | 1652 | __func__, ssh_err(r)); |
@@ -1890,13 +1905,22 @@ hostkeys_find(struct hostkey_foreach_line *l, void *_ctx) | |||
1890 | } | 1905 | } |
1891 | 1906 | ||
1892 | static void | 1907 | static void |
1908 | hostkey_change_preamble(LogLevel loglevel) | ||
1909 | { | ||
1910 | do_log2(loglevel, "The server has updated its host keys."); | ||
1911 | do_log2(loglevel, "These changes were verified by the server's " | ||
1912 | "existing trusted key."); | ||
1913 | } | ||
1914 | |||
1915 | static void | ||
1893 | update_known_hosts(struct hostkeys_update_ctx *ctx) | 1916 | update_known_hosts(struct hostkeys_update_ctx *ctx) |
1894 | { | 1917 | { |
1895 | int r, was_raw = 0; | 1918 | int r, was_raw = 0, first = 1; |
1896 | LogLevel loglevel = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK ? | 1919 | int asking = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK; |
1897 | SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE; | 1920 | LogLevel loglevel = asking ? SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE; |
1898 | char *fp, *response; | 1921 | char *fp, *response; |
1899 | size_t i; | 1922 | size_t i; |
1923 | struct stat sb; | ||
1900 | 1924 | ||
1901 | for (i = 0; i < ctx->nkeys; i++) { | 1925 | for (i = 0; i < ctx->nkeys; i++) { |
1902 | if (ctx->keys_seen[i] != 2) | 1926 | if (ctx->keys_seen[i] != 2) |
@@ -1904,16 +1928,22 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) | |||
1904 | if ((fp = sshkey_fingerprint(ctx->keys[i], | 1928 | if ((fp = sshkey_fingerprint(ctx->keys[i], |
1905 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) | 1929 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
1906 | fatal("%s: sshkey_fingerprint failed", __func__); | 1930 | fatal("%s: sshkey_fingerprint failed", __func__); |
1931 | if (first && asking) | ||
1932 | hostkey_change_preamble(loglevel); | ||
1907 | do_log2(loglevel, "Learned new hostkey: %s %s", | 1933 | do_log2(loglevel, "Learned new hostkey: %s %s", |
1908 | sshkey_type(ctx->keys[i]), fp); | 1934 | sshkey_type(ctx->keys[i]), fp); |
1935 | first = 0; | ||
1909 | free(fp); | 1936 | free(fp); |
1910 | } | 1937 | } |
1911 | for (i = 0; i < ctx->nold; i++) { | 1938 | for (i = 0; i < ctx->nold; i++) { |
1912 | if ((fp = sshkey_fingerprint(ctx->old_keys[i], | 1939 | if ((fp = sshkey_fingerprint(ctx->old_keys[i], |
1913 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) | 1940 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
1914 | fatal("%s: sshkey_fingerprint failed", __func__); | 1941 | fatal("%s: sshkey_fingerprint failed", __func__); |
1942 | if (first && asking) | ||
1943 | hostkey_change_preamble(loglevel); | ||
1915 | do_log2(loglevel, "Deprecating obsolete hostkey: %s %s", | 1944 | do_log2(loglevel, "Deprecating obsolete hostkey: %s %s", |
1916 | sshkey_type(ctx->old_keys[i]), fp); | 1945 | sshkey_type(ctx->old_keys[i]), fp); |
1946 | first = 0; | ||
1917 | free(fp); | 1947 | free(fp); |
1918 | } | 1948 | } |
1919 | if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { | 1949 | if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { |
@@ -1943,19 +1973,37 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) | |||
1943 | if (was_raw) | 1973 | if (was_raw) |
1944 | enter_raw_mode(1); | 1974 | enter_raw_mode(1); |
1945 | } | 1975 | } |
1946 | 1976 | if (options.update_hostkeys == 0) | |
1977 | return; | ||
1947 | /* | 1978 | /* |
1948 | * Now that all the keys are verified, we can go ahead and replace | 1979 | * Now that all the keys are verified, we can go ahead and replace |
1949 | * them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't | 1980 | * them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't |
1950 | * cancel the operation). | 1981 | * cancel the operation). |
1951 | */ | 1982 | */ |
1952 | if (options.update_hostkeys != 0 && | 1983 | for (i = 0; i < options.num_user_hostfiles; i++) { |
1953 | (r = hostfile_replace_entries(options.user_hostfiles[0], | 1984 | /* |
1954 | ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys, | 1985 | * NB. keys are only added to hostfiles[0], for the rest we |
1955 | options.hash_known_hosts, 0, | 1986 | * just delete the hostname entries. |
1956 | options.fingerprint_hash)) != 0) | 1987 | */ |
1957 | error("%s: hostfile_replace_entries failed: %s", | 1988 | if (stat(options.user_hostfiles[i], &sb) != 0) { |
1958 | __func__, ssh_err(r)); | 1989 | if (errno == ENOENT) { |
1990 | debug("%s: known hosts file %s does not exist", | ||
1991 | __func__, strerror(errno)); | ||
1992 | } else { | ||
1993 | error("%s: known hosts file %s inaccessible", | ||
1994 | __func__, strerror(errno)); | ||
1995 | } | ||
1996 | continue; | ||
1997 | } | ||
1998 | if ((r = hostfile_replace_entries(options.user_hostfiles[i], | ||
1999 | ctx->host_str, ctx->ip_str, | ||
2000 | i == 0 ? ctx->keys : NULL, i == 0 ? ctx->nkeys : 0, | ||
2001 | options.hash_known_hosts, 0, | ||
2002 | options.fingerprint_hash)) != 0) { | ||
2003 | error("%s: hostfile_replace_entries failed for %s: %s", | ||
2004 | __func__, options.user_hostfiles[i], ssh_err(r)); | ||
2005 | } | ||
2006 | } | ||
1959 | } | 2007 | } |
1960 | 2008 | ||
1961 | static void | 2009 | static void |
@@ -2016,7 +2064,8 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type, | |||
2016 | sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; | 2064 | sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; |
2017 | if ((r = sshkey_verify(ctx->keys[i], sig, siglen, | 2065 | if ((r = sshkey_verify(ctx->keys[i], sig, siglen, |
2018 | sshbuf_ptr(signdata), sshbuf_len(signdata), | 2066 | sshbuf_ptr(signdata), sshbuf_len(signdata), |
2019 | use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0)) != 0) { | 2067 | use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, |
2068 | NULL)) != 0) { | ||
2020 | error("%s: server gave bad signature for %s key %zu", | 2069 | error("%s: server gave bad signature for %s key %zu", |
2021 | __func__, sshkey_type(ctx->keys[i]), i); | 2070 | __func__, sshkey_type(ctx->keys[i]), i); |
2022 | goto out; | 2071 | goto out; |
@@ -2047,8 +2096,7 @@ static int | |||
2047 | key_accepted_by_hostkeyalgs(const struct sshkey *key) | 2096 | key_accepted_by_hostkeyalgs(const struct sshkey *key) |
2048 | { | 2097 | { |
2049 | const char *ktype = sshkey_ssh_name(key); | 2098 | const char *ktype = sshkey_ssh_name(key); |
2050 | const char *hostkeyalgs = options.hostkeyalgorithms != NULL ? | 2099 | const char *hostkeyalgs = options.hostkeyalgorithms; |
2051 | options.hostkeyalgorithms : KEX_DEFAULT_PK_ALG; | ||
2052 | 2100 | ||
2053 | if (key == NULL || key->type == KEY_UNSPEC) | 2101 | if (key == NULL || key->type == KEY_UNSPEC) |
2054 | return 0; | 2102 | return 0; |
@@ -2095,8 +2143,10 @@ client_input_hostkeys(struct ssh *ssh) | |||
2095 | goto out; | 2143 | goto out; |
2096 | } | 2144 | } |
2097 | if ((r = sshkey_from_blob(blob, len, &key)) != 0) { | 2145 | if ((r = sshkey_from_blob(blob, len, &key)) != 0) { |
2098 | error("%s: parse key: %s", __func__, ssh_err(r)); | 2146 | do_log2(r == SSH_ERR_KEY_TYPE_UNKNOWN ? |
2099 | goto out; | 2147 | SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_ERROR, |
2148 | "%s: parse key: %s", __func__, ssh_err(r)); | ||
2149 | continue; | ||
2100 | } | 2150 | } |
2101 | fp = sshkey_fingerprint(key, options.fingerprint_hash, | 2151 | fp = sshkey_fingerprint(key, options.fingerprint_hash, |
2102 | SSH_FP_DEFAULT); | 2152 | SSH_FP_DEFAULT); |
@@ -2148,11 +2198,22 @@ client_input_hostkeys(struct ssh *ssh) | |||
2148 | options.check_host_ip ? &ctx->ip_str : NULL); | 2198 | options.check_host_ip ? &ctx->ip_str : NULL); |
2149 | 2199 | ||
2150 | /* Find which keys we already know about. */ | 2200 | /* Find which keys we already know about. */ |
2151 | if ((r = hostkeys_foreach(options.user_hostfiles[0], hostkeys_find, | 2201 | for (i = 0; i < options.num_user_hostfiles; i++) { |
2152 | ctx, ctx->host_str, ctx->ip_str, | 2202 | debug("%s: searching %s for %s / %s", __func__, |
2153 | HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { | 2203 | options.user_hostfiles[i], ctx->host_str, |
2154 | error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); | 2204 | ctx->ip_str ? ctx->ip_str : "(none)"); |
2155 | goto out; | 2205 | if ((r = hostkeys_foreach(options.user_hostfiles[i], |
2206 | hostkeys_find, ctx, ctx->host_str, ctx->ip_str, | ||
2207 | HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { | ||
2208 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { | ||
2209 | debug("%s: hostkeys file %s does not exist", | ||
2210 | __func__, options.user_hostfiles[i]); | ||
2211 | continue; | ||
2212 | } | ||
2213 | error("%s: hostkeys_foreach failed for %s: %s", | ||
2214 | __func__, options.user_hostfiles[i], ssh_err(r)); | ||
2215 | goto out; | ||
2216 | } | ||
2156 | } | 2217 | } |
2157 | 2218 | ||
2158 | /* Figure out if we have any new keys to add */ | 2219 | /* Figure out if we have any new keys to add */ |