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 |
@@ -840,7 +840,7 @@ notify_hostkeys(struct ssh *ssh) | |||
840 | * all connections are dropped for startups > max_startups | 840 | * all connections are dropped for startups > max_startups |
841 | */ | 841 | */ |
842 | static int | 842 | static int |
843 | drop_connection(int startups) | 843 | should_drop_connection(int startups) |
844 | { | 844 | { |
845 | int p, r; | 845 | int p, r; |
846 | 846 | ||
@@ -857,10 +857,68 @@ drop_connection(int startups) | |||
857 | p += options.max_startups_rate; | 857 | p += options.max_startups_rate; |
858 | r = arc4random_uniform(100); | 858 | r = arc4random_uniform(100); |
859 | 859 | ||
860 | debug("drop_connection: p %d, r %d", p, r); | 860 | debug("%s: p %d, r %d", __func__, p, r); |
861 | return (r < p) ? 1 : 0; | 861 | return (r < p) ? 1 : 0; |
862 | } | 862 | } |
863 | 863 | ||
864 | /* | ||
865 | * Check whether connection should be accepted by MaxStartups. | ||
866 | * Returns 0 if the connection is accepted. If the connection is refused, | ||
867 | * returns 1 and attempts to send notification to client. | ||
868 | * Logs when the MaxStartups condition is entered or exited, and periodically | ||
869 | * while in that state. | ||
870 | */ | ||
871 | static int | ||
872 | drop_connection(int sock, int startups) | ||
873 | { | ||
874 | char *laddr, *raddr; | ||
875 | const char msg[] = "Exceeded MaxStartups\r\n"; | ||
876 | static time_t last_drop, first_drop; | ||
877 | static u_int ndropped; | ||
878 | LogLevel drop_level = SYSLOG_LEVEL_VERBOSE; | ||
879 | time_t now; | ||
880 | |||
881 | now = monotime(); | ||
882 | if (!should_drop_connection(startups)) { | ||
883 | if (last_drop != 0 && | ||
884 | startups < options.max_startups_begin - 1) { | ||
885 | /* XXX maybe need better hysteresis here */ | ||
886 | logit("exited MaxStartups throttling after %s, " | ||
887 | "%u connections dropped", | ||
888 | fmt_timeframe(now - first_drop), ndropped); | ||
889 | last_drop = 0; | ||
890 | } | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | #define SSHD_MAXSTARTUPS_LOG_INTERVAL (5 * 60) | ||
895 | if (last_drop == 0) { | ||
896 | error("beginning MaxStartups throttling"); | ||
897 | drop_level = SYSLOG_LEVEL_INFO; | ||
898 | first_drop = now; | ||
899 | ndropped = 0; | ||
900 | } else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) { | ||
901 | /* Periodic logs */ | ||
902 | error("in MaxStartups throttling for %s, " | ||
903 | "%u connections dropped", | ||
904 | fmt_timeframe(now - first_drop), ndropped + 1); | ||
905 | drop_level = SYSLOG_LEVEL_INFO; | ||
906 | } | ||
907 | last_drop = now; | ||
908 | ndropped++; | ||
909 | |||
910 | laddr = get_local_ipaddr(sock); | ||
911 | raddr = get_peer_ipaddr(sock); | ||
912 | do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d " | ||
913 | "past MaxStartups", startups, raddr, get_peer_port(sock), | ||
914 | laddr, get_local_port(sock)); | ||
915 | free(laddr); | ||
916 | free(raddr); | ||
917 | /* best-effort notification to client */ | ||
918 | (void)write(sock, msg, sizeof(msg) - 1); | ||
919 | return 1; | ||
920 | } | ||
921 | |||
864 | static void | 922 | static void |
865 | usage(void) | 923 | usage(void) |
866 | { | 924 | { |
@@ -918,7 +976,7 @@ send_rexec_state(int fd, struct sshbuf *conf) | |||
918 | rexec_send_rng_seed(m); | 976 | rexec_send_rng_seed(m); |
919 | #endif | 977 | #endif |
920 | if (ssh_msg_send(fd, 0, m) == -1) | 978 | if (ssh_msg_send(fd, 0, m) == -1) |
921 | fatal("%s: ssh_msg_send failed", __func__); | 979 | error("%s: ssh_msg_send failed", __func__); |
922 | 980 | ||
923 | sshbuf_free(m); | 981 | sshbuf_free(m); |
924 | sshbuf_free(inc); | 982 | sshbuf_free(inc); |
@@ -1217,27 +1275,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | |||
1217 | usleep(100 * 1000); | 1275 | usleep(100 * 1000); |
1218 | continue; | 1276 | continue; |
1219 | } | 1277 | } |
1220 | if (unset_nonblock(*newsock) == -1) { | 1278 | if (unset_nonblock(*newsock) == -1 || |
1221 | close(*newsock); | 1279 | drop_connection(*newsock, startups) || |
1222 | continue; | 1280 | pipe(startup_p) == -1) { |
1223 | } | ||
1224 | if (drop_connection(startups) == 1) { | ||
1225 | char *laddr = get_local_ipaddr(*newsock); | ||
1226 | char *raddr = get_peer_ipaddr(*newsock); | ||
1227 | char msg[] = "Exceeded MaxStartups\r\n"; | ||
1228 | |||
1229 | verbose("drop connection #%d from [%s]:%d " | ||
1230 | "on [%s]:%d past MaxStartups", startups, | ||
1231 | raddr, get_peer_port(*newsock), | ||
1232 | laddr, get_local_port(*newsock)); | ||
1233 | free(laddr); | ||
1234 | free(raddr); | ||
1235 | /* best-effort notification to client */ | ||
1236 | (void)write(*newsock, msg, strlen(msg)); | ||
1237 | close(*newsock); | ||
1238 | continue; | ||
1239 | } | ||
1240 | if (pipe(startup_p) == -1) { | ||
1241 | close(*newsock); | 1281 | close(*newsock); |
1242 | continue; | 1282 | continue; |
1243 | } | 1283 | } |
@@ -1339,9 +1379,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | |||
1339 | close(startup_p[1]); | 1379 | close(startup_p[1]); |
1340 | 1380 | ||
1341 | if (rexec_flag) { | 1381 | if (rexec_flag) { |
1382 | close(config_s[1]); | ||
1342 | send_rexec_state(config_s[0], cfg); | 1383 | send_rexec_state(config_s[0], cfg); |
1343 | close(config_s[0]); | 1384 | close(config_s[0]); |
1344 | close(config_s[1]); | ||
1345 | } | 1385 | } |
1346 | close(*newsock); | 1386 | close(*newsock); |
1347 | 1387 | ||
@@ -1697,6 +1737,7 @@ main(int ac, char **av) | |||
1697 | if ((cfg = sshbuf_new()) == NULL) | 1737 | if ((cfg = sshbuf_new()) == NULL) |
1698 | fatal("%s: sshbuf_new failed", __func__); | 1738 | fatal("%s: sshbuf_new failed", __func__); |
1699 | if (rexeced_flag) { | 1739 | if (rexeced_flag) { |
1740 | setproctitle("%s", "[rexeced]"); | ||
1700 | recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg); | 1741 | recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg); |
1701 | if (!debug_flag) { | 1742 | if (!debug_flag) { |
1702 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | 1743 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); |
@@ -1820,10 +1861,19 @@ main(int ac, char **av) | |||
1820 | &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) | 1861 | &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) |
1821 | do_log2(ll, "Unable to load host key \"%s\": %s", | 1862 | do_log2(ll, "Unable to load host key \"%s\": %s", |
1822 | options.host_key_files[i], ssh_err(r)); | 1863 | options.host_key_files[i], ssh_err(r)); |
1823 | if (pubkey == NULL && key != NULL) | 1864 | if (pubkey != NULL && key != NULL) { |
1865 | if (!sshkey_equal(pubkey, key)) { | ||
1866 | error("Public key for %s does not match " | ||
1867 | "private key", options.host_key_files[i]); | ||
1868 | sshkey_free(pubkey); | ||
1869 | pubkey = NULL; | ||
1870 | } | ||
1871 | } | ||
1872 | if (pubkey == NULL && key != NULL) { | ||
1824 | if ((r = sshkey_from_private(key, &pubkey)) != 0) | 1873 | if ((r = sshkey_from_private(key, &pubkey)) != 0) |
1825 | fatal("Could not demote key: \"%s\": %s", | 1874 | fatal("Could not demote key: \"%s\": %s", |
1826 | options.host_key_files[i], ssh_err(r)); | 1875 | options.host_key_files[i], ssh_err(r)); |
1876 | } | ||
1827 | sensitive_data.host_keys[i] = key; | 1877 | sensitive_data.host_keys[i] = key; |
1828 | sensitive_data.host_pubkeys[i] = pubkey; | 1878 | sensitive_data.host_pubkeys[i] = pubkey; |
1829 | 1879 | ||
@@ -2076,6 +2126,7 @@ main(int ac, char **av) | |||
2076 | dup2(config_s[1], REEXEC_CONFIG_PASS_FD); | 2126 | dup2(config_s[1], REEXEC_CONFIG_PASS_FD); |
2077 | close(config_s[1]); | 2127 | close(config_s[1]); |
2078 | 2128 | ||
2129 | ssh_signal(SIGHUP, SIG_IGN); /* avoid reset to SIG_DFL */ | ||
2079 | execv(rexec_argv[0], rexec_argv); | 2130 | execv(rexec_argv[0], rexec_argv); |
2080 | 2131 | ||
2081 | /* Reexec has failed, fall back and continue */ | 2132 | /* Reexec has failed, fall back and continue */ |
@@ -2322,19 +2373,19 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, | |||
2322 | if (use_privsep) { | 2373 | if (use_privsep) { |
2323 | if (privkey) { | 2374 | if (privkey) { |
2324 | if (mm_sshkey_sign(ssh, privkey, signature, slenp, | 2375 | if (mm_sshkey_sign(ssh, privkey, signature, slenp, |
2325 | data, dlen, alg, options.sk_provider, | 2376 | data, dlen, alg, options.sk_provider, NULL, |
2326 | ssh->compat) < 0) | 2377 | ssh->compat) < 0) |
2327 | fatal("%s: privkey sign failed", __func__); | 2378 | fatal("%s: privkey sign failed", __func__); |
2328 | } else { | 2379 | } else { |
2329 | if (mm_sshkey_sign(ssh, pubkey, signature, slenp, | 2380 | if (mm_sshkey_sign(ssh, pubkey, signature, slenp, |
2330 | data, dlen, alg, options.sk_provider, | 2381 | data, dlen, alg, options.sk_provider, NULL, |
2331 | ssh->compat) < 0) | 2382 | ssh->compat) < 0) |
2332 | fatal("%s: pubkey sign failed", __func__); | 2383 | fatal("%s: pubkey sign failed", __func__); |
2333 | } | 2384 | } |
2334 | } else { | 2385 | } else { |
2335 | if (privkey) { | 2386 | if (privkey) { |
2336 | if (sshkey_sign(privkey, signature, slenp, data, dlen, | 2387 | if (sshkey_sign(privkey, signature, slenp, data, dlen, |
2337 | alg, options.sk_provider, ssh->compat) < 0) | 2388 | alg, options.sk_provider, NULL, ssh->compat) < 0) |
2338 | fatal("%s: privkey sign failed", __func__); | 2389 | fatal("%s: privkey sign failed", __func__); |
2339 | } else { | 2390 | } else { |
2340 | if ((r = ssh_agent_sign(auth_sock, pubkey, | 2391 | if ((r = ssh_agent_sign(auth_sock, pubkey, |
@@ -2460,10 +2511,11 @@ do_ssh2_kex(struct ssh *ssh) | |||
2460 | 2511 | ||
2461 | #ifdef DEBUG_KEXDH | 2512 | #ifdef DEBUG_KEXDH |
2462 | /* send 1st encrypted/maced/compressed message */ | 2513 | /* send 1st encrypted/maced/compressed message */ |
2463 | packet_start(SSH2_MSG_IGNORE); | 2514 | if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || |
2464 | packet_put_cstring("markus"); | 2515 | (r = sshpkt_put_cstring(ssh, "markus")) != 0 || |
2465 | packet_send(); | 2516 | (r = sshpkt_send(ssh)) != 0 || |
2466 | packet_write_wait(); | 2517 | (r = ssh_packet_write_wait(ssh)) != 0) |
2518 | fatal("%s: send test: %s", __func__, ssh_err(r)); | ||
2467 | #endif | 2519 | #endif |
2468 | debug("KEX done"); | 2520 | debug("KEX done"); |
2469 | } | 2521 | } |