diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 120 |
1 files changed, 86 insertions, 34 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.552 2020/03/13 04:01:57 djm Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.561 2020/08/27 01:06:19 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 |
@@ -829,7 +829,7 @@ notify_hostkeys(struct ssh *ssh) | |||
829 | * all connections are dropped for startups > max_startups | 829 | * all connections are dropped for startups > max_startups |
830 | */ | 830 | */ |
831 | static int | 831 | static int |
832 | drop_connection(int startups) | 832 | should_drop_connection(int startups) |
833 | { | 833 | { |
834 | int p, r; | 834 | int p, r; |
835 | 835 | ||
@@ -846,10 +846,68 @@ drop_connection(int startups) | |||
846 | p += options.max_startups_rate; | 846 | p += options.max_startups_rate; |
847 | r = arc4random_uniform(100); | 847 | r = arc4random_uniform(100); |
848 | 848 | ||
849 | debug("drop_connection: p %d, r %d", p, r); | 849 | debug("%s: p %d, r %d", __func__, p, r); |
850 | return (r < p) ? 1 : 0; | 850 | return (r < p) ? 1 : 0; |
851 | } | 851 | } |
852 | 852 | ||
853 | /* | ||
854 | * Check whether connection should be accepted by MaxStartups. | ||
855 | * Returns 0 if the connection is accepted. If the connection is refused, | ||
856 | * returns 1 and attempts to send notification to client. | ||
857 | * Logs when the MaxStartups condition is entered or exited, and periodically | ||
858 | * while in that state. | ||
859 | */ | ||
860 | static int | ||
861 | drop_connection(int sock, int startups) | ||
862 | { | ||
863 | char *laddr, *raddr; | ||
864 | const char msg[] = "Exceeded MaxStartups\r\n"; | ||
865 | static time_t last_drop, first_drop; | ||
866 | static u_int ndropped; | ||
867 | LogLevel drop_level = SYSLOG_LEVEL_VERBOSE; | ||
868 | time_t now; | ||
869 | |||
870 | now = monotime(); | ||
871 | if (!should_drop_connection(startups)) { | ||
872 | if (last_drop != 0 && | ||
873 | startups < options.max_startups_begin - 1) { | ||
874 | /* XXX maybe need better hysteresis here */ | ||
875 | logit("exited MaxStartups throttling after %s, " | ||
876 | "%u connections dropped", | ||
877 | fmt_timeframe(now - first_drop), ndropped); | ||
878 | last_drop = 0; | ||
879 | } | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | #define SSHD_MAXSTARTUPS_LOG_INTERVAL (5 * 60) | ||
884 | if (last_drop == 0) { | ||
885 | error("beginning MaxStartups throttling"); | ||
886 | drop_level = SYSLOG_LEVEL_INFO; | ||
887 | first_drop = now; | ||
888 | ndropped = 0; | ||
889 | } else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) { | ||
890 | /* Periodic logs */ | ||
891 | error("in MaxStartups throttling for %s, " | ||
892 | "%u connections dropped", | ||
893 | fmt_timeframe(now - first_drop), ndropped + 1); | ||
894 | drop_level = SYSLOG_LEVEL_INFO; | ||
895 | } | ||
896 | last_drop = now; | ||
897 | ndropped++; | ||
898 | |||
899 | laddr = get_local_ipaddr(sock); | ||
900 | raddr = get_peer_ipaddr(sock); | ||
901 | do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d " | ||
902 | "past MaxStartups", startups, raddr, get_peer_port(sock), | ||
903 | laddr, get_local_port(sock)); | ||
904 | free(laddr); | ||
905 | free(raddr); | ||
906 | /* best-effort notification to client */ | ||
907 | (void)write(sock, msg, sizeof(msg) - 1); | ||
908 | return 1; | ||
909 | } | ||
910 | |||
853 | static void | 911 | static void |
854 | usage(void) | 912 | usage(void) |
855 | { | 913 | { |
@@ -907,7 +965,7 @@ send_rexec_state(int fd, struct sshbuf *conf) | |||
907 | rexec_send_rng_seed(m); | 965 | rexec_send_rng_seed(m); |
908 | #endif | 966 | #endif |
909 | if (ssh_msg_send(fd, 0, m) == -1) | 967 | if (ssh_msg_send(fd, 0, m) == -1) |
910 | fatal("%s: ssh_msg_send failed", __func__); | 968 | error("%s: ssh_msg_send failed", __func__); |
911 | 969 | ||
912 | sshbuf_free(m); | 970 | sshbuf_free(m); |
913 | sshbuf_free(inc); | 971 | sshbuf_free(inc); |
@@ -1206,27 +1264,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | |||
1206 | usleep(100 * 1000); | 1264 | usleep(100 * 1000); |
1207 | continue; | 1265 | continue; |
1208 | } | 1266 | } |
1209 | if (unset_nonblock(*newsock) == -1) { | 1267 | if (unset_nonblock(*newsock) == -1 || |
1210 | close(*newsock); | 1268 | drop_connection(*newsock, startups) || |
1211 | continue; | 1269 | pipe(startup_p) == -1) { |
1212 | } | ||
1213 | if (drop_connection(startups) == 1) { | ||
1214 | char *laddr = get_local_ipaddr(*newsock); | ||
1215 | char *raddr = get_peer_ipaddr(*newsock); | ||
1216 | char msg[] = "Exceeded MaxStartups\r\n"; | ||
1217 | |||
1218 | verbose("drop connection #%d from [%s]:%d " | ||
1219 | "on [%s]:%d past MaxStartups", startups, | ||
1220 | raddr, get_peer_port(*newsock), | ||
1221 | laddr, get_local_port(*newsock)); | ||
1222 | free(laddr); | ||
1223 | free(raddr); | ||
1224 | /* best-effort notification to client */ | ||
1225 | (void)write(*newsock, msg, strlen(msg)); | ||
1226 | close(*newsock); | ||
1227 | continue; | ||
1228 | } | ||
1229 | if (pipe(startup_p) == -1) { | ||
1230 | close(*newsock); | 1270 | close(*newsock); |
1231 | continue; | 1271 | continue; |
1232 | } | 1272 | } |
@@ -1328,9 +1368,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | |||
1328 | close(startup_p[1]); | 1368 | close(startup_p[1]); |
1329 | 1369 | ||
1330 | if (rexec_flag) { | 1370 | if (rexec_flag) { |
1371 | close(config_s[1]); | ||
1331 | send_rexec_state(config_s[0], cfg); | 1372 | send_rexec_state(config_s[0], cfg); |
1332 | close(config_s[0]); | 1373 | close(config_s[0]); |
1333 | close(config_s[1]); | ||
1334 | } | 1374 | } |
1335 | close(*newsock); | 1375 | close(*newsock); |
1336 | 1376 | ||
@@ -1686,6 +1726,7 @@ main(int ac, char **av) | |||
1686 | if ((cfg = sshbuf_new()) == NULL) | 1726 | if ((cfg = sshbuf_new()) == NULL) |
1687 | fatal("%s: sshbuf_new failed", __func__); | 1727 | fatal("%s: sshbuf_new failed", __func__); |
1688 | if (rexeced_flag) { | 1728 | if (rexeced_flag) { |
1729 | setproctitle("%s", "[rexeced]"); | ||
1689 | recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg); | 1730 | recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg); |
1690 | if (!debug_flag) { | 1731 | if (!debug_flag) { |
1691 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | 1732 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); |
@@ -1809,10 +1850,19 @@ main(int ac, char **av) | |||
1809 | &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) | 1850 | &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) |
1810 | do_log2(ll, "Unable to load host key \"%s\": %s", | 1851 | do_log2(ll, "Unable to load host key \"%s\": %s", |
1811 | options.host_key_files[i], ssh_err(r)); | 1852 | options.host_key_files[i], ssh_err(r)); |
1812 | if (pubkey == NULL && key != NULL) | 1853 | if (pubkey != NULL && key != NULL) { |
1854 | if (!sshkey_equal(pubkey, key)) { | ||
1855 | error("Public key for %s does not match " | ||
1856 | "private key", options.host_key_files[i]); | ||
1857 | sshkey_free(pubkey); | ||
1858 | pubkey = NULL; | ||
1859 | } | ||
1860 | } | ||
1861 | if (pubkey == NULL && key != NULL) { | ||
1813 | if ((r = sshkey_from_private(key, &pubkey)) != 0) | 1862 | if ((r = sshkey_from_private(key, &pubkey)) != 0) |
1814 | fatal("Could not demote key: \"%s\": %s", | 1863 | fatal("Could not demote key: \"%s\": %s", |
1815 | options.host_key_files[i], ssh_err(r)); | 1864 | options.host_key_files[i], ssh_err(r)); |
1865 | } | ||
1816 | sensitive_data.host_keys[i] = key; | 1866 | sensitive_data.host_keys[i] = key; |
1817 | sensitive_data.host_pubkeys[i] = pubkey; | 1867 | sensitive_data.host_pubkeys[i] = pubkey; |
1818 | 1868 | ||
@@ -2059,6 +2109,7 @@ main(int ac, char **av) | |||
2059 | dup2(config_s[1], REEXEC_CONFIG_PASS_FD); | 2109 | dup2(config_s[1], REEXEC_CONFIG_PASS_FD); |
2060 | close(config_s[1]); | 2110 | close(config_s[1]); |
2061 | 2111 | ||
2112 | ssh_signal(SIGHUP, SIG_IGN); /* avoid reset to SIG_DFL */ | ||
2062 | execv(rexec_argv[0], rexec_argv); | 2113 | execv(rexec_argv[0], rexec_argv); |
2063 | 2114 | ||
2064 | /* Reexec has failed, fall back and continue */ | 2115 | /* Reexec has failed, fall back and continue */ |
@@ -2287,19 +2338,19 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, | |||
2287 | if (use_privsep) { | 2338 | if (use_privsep) { |
2288 | if (privkey) { | 2339 | if (privkey) { |
2289 | if (mm_sshkey_sign(ssh, privkey, signature, slenp, | 2340 | if (mm_sshkey_sign(ssh, privkey, signature, slenp, |
2290 | data, dlen, alg, options.sk_provider, | 2341 | data, dlen, alg, options.sk_provider, NULL, |
2291 | ssh->compat) < 0) | 2342 | ssh->compat) < 0) |
2292 | fatal("%s: privkey sign failed", __func__); | 2343 | fatal("%s: privkey sign failed", __func__); |
2293 | } else { | 2344 | } else { |
2294 | if (mm_sshkey_sign(ssh, pubkey, signature, slenp, | 2345 | if (mm_sshkey_sign(ssh, pubkey, signature, slenp, |
2295 | data, dlen, alg, options.sk_provider, | 2346 | data, dlen, alg, options.sk_provider, NULL, |
2296 | ssh->compat) < 0) | 2347 | ssh->compat) < 0) |
2297 | fatal("%s: pubkey sign failed", __func__); | 2348 | fatal("%s: pubkey sign failed", __func__); |
2298 | } | 2349 | } |
2299 | } else { | 2350 | } else { |
2300 | if (privkey) { | 2351 | if (privkey) { |
2301 | if (sshkey_sign(privkey, signature, slenp, data, dlen, | 2352 | if (sshkey_sign(privkey, signature, slenp, data, dlen, |
2302 | alg, options.sk_provider, ssh->compat) < 0) | 2353 | alg, options.sk_provider, NULL, ssh->compat) < 0) |
2303 | fatal("%s: privkey sign failed", __func__); | 2354 | fatal("%s: privkey sign failed", __func__); |
2304 | } else { | 2355 | } else { |
2305 | if ((r = ssh_agent_sign(auth_sock, pubkey, | 2356 | if ((r = ssh_agent_sign(auth_sock, pubkey, |
@@ -2372,10 +2423,11 @@ do_ssh2_kex(struct ssh *ssh) | |||
2372 | 2423 | ||
2373 | #ifdef DEBUG_KEXDH | 2424 | #ifdef DEBUG_KEXDH |
2374 | /* send 1st encrypted/maced/compressed message */ | 2425 | /* send 1st encrypted/maced/compressed message */ |
2375 | packet_start(SSH2_MSG_IGNORE); | 2426 | if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || |
2376 | packet_put_cstring("markus"); | 2427 | (r = sshpkt_put_cstring(ssh, "markus")) != 0 || |
2377 | packet_send(); | 2428 | (r = sshpkt_send(ssh)) != 0 || |
2378 | packet_write_wait(); | 2429 | (r = ssh_packet_write_wait(ssh)) != 0) |
2430 | fatal("%s: send test: %s", __func__, ssh_err(r)); | ||
2379 | #endif | 2431 | #endif |
2380 | debug("KEX done"); | 2432 | debug("KEX done"); |
2381 | } | 2433 | } |