diff options
author | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
commit | efd3d4522636ae029488c2e9730b60c88e257d2e (patch) | |
tree | 31e02ac3f16090ce8c53448677356b2b7f423683 /sshd.c | |
parent | bbec4db36d464ea1d464a707625125f9fd5c7b5e (diff) | |
parent | d1a87e462e1db89f19cd960588d0c6b287cb5ccc (diff) |
* New upstream release (LP: #535029).
- After a transition period of about 10 years, this release disables SSH
protocol 1 by default. Clients and servers that need to use the
legacy protocol must explicitly enable it in ssh_config / sshd_config
or on the command-line.
- Remove the libsectok/OpenSC-based smartcard code and add support for
PKCS#11 tokens. This support is enabled by default in the Debian
packaging, since it now doesn't involve additional library
dependencies (closes: #231472, LP: #16918).
- Add support for certificate authentication of users and hosts using a
new, minimal OpenSSH certificate format (closes: #482806).
- Added a 'netcat mode' to ssh(1): "ssh -W host:port ...".
- Add the ability to revoke keys in sshd(8) and ssh(1). (For the Debian
package, this overlaps with the key blacklisting facility added in
openssh 1:4.7p1-9, but with different file formats and slightly
different scopes; for the moment, I've roughly merged the two.)
- Various multiplexing improvements, including support for requesting
port-forwardings via the multiplex protocol (closes: #360151).
- Allow setting an explicit umask on the sftp-server(8) commandline to
override whatever default the user has (closes: #496843).
- Many sftp client improvements, including tab-completion, more options,
and recursive transfer support for get/put (LP: #33378). The old
mget/mput commands never worked properly and have been removed
(closes: #270399, #428082).
- Do not prompt for a passphrase if we fail to open a keyfile, and log
the reason why the open failed to debug (closes: #431538).
- Prevent sftp from crashing when given a "-" without a command. Also,
allow whitespace to follow a "-" (closes: #531561).
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 177 |
1 files changed, 115 insertions, 62 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.367 2009/05/28 16:50:16 andreas Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.374 2010/03/07 11:57:13 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 |
@@ -209,6 +209,7 @@ struct { | |||
209 | Key *server_key; /* ephemeral server key */ | 209 | Key *server_key; /* ephemeral server key */ |
210 | Key *ssh1_host_key; /* ssh1 host key */ | 210 | Key *ssh1_host_key; /* ssh1 host key */ |
211 | Key **host_keys; /* all private host keys */ | 211 | Key **host_keys; /* all private host keys */ |
212 | Key **host_certificates; /* all public host certificates */ | ||
212 | int have_ssh1_key; | 213 | int have_ssh1_key; |
213 | int have_ssh2_key; | 214 | int have_ssh2_key; |
214 | u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; | 215 | u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; |
@@ -254,11 +255,6 @@ Buffer loginmsg; | |||
254 | /* Unprivileged user */ | 255 | /* Unprivileged user */ |
255 | struct passwd *privsep_pw = NULL; | 256 | struct passwd *privsep_pw = NULL; |
256 | 257 | ||
257 | #ifdef OOM_ADJUST | ||
258 | /* Linux out-of-memory killer adjustment */ | ||
259 | static char oom_adj_save[8]; | ||
260 | #endif | ||
261 | |||
262 | /* Prototypes for various functions defined later in this file. */ | 258 | /* Prototypes for various functions defined later in this file. */ |
263 | void destroy_sensitive_data(void); | 259 | void destroy_sensitive_data(void); |
264 | void demote_sensitive_data(void); | 260 | void demote_sensitive_data(void); |
@@ -555,6 +551,10 @@ destroy_sensitive_data(void) | |||
555 | key_free(sensitive_data.host_keys[i]); | 551 | key_free(sensitive_data.host_keys[i]); |
556 | sensitive_data.host_keys[i] = NULL; | 552 | sensitive_data.host_keys[i] = NULL; |
557 | } | 553 | } |
554 | if (sensitive_data.host_certificates[i]) { | ||
555 | key_free(sensitive_data.host_certificates[i]); | ||
556 | sensitive_data.host_certificates[i] = NULL; | ||
557 | } | ||
558 | } | 558 | } |
559 | sensitive_data.ssh1_host_key = NULL; | 559 | sensitive_data.ssh1_host_key = NULL; |
560 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); | 560 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); |
@@ -581,6 +581,7 @@ demote_sensitive_data(void) | |||
581 | if (tmp->type == KEY_RSA1) | 581 | if (tmp->type == KEY_RSA1) |
582 | sensitive_data.ssh1_host_key = tmp; | 582 | sensitive_data.ssh1_host_key = tmp; |
583 | } | 583 | } |
584 | /* Certs do not need demotion */ | ||
584 | } | 585 | } |
585 | 586 | ||
586 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ | 587 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ |
@@ -727,10 +728,11 @@ list_hostkey_types(void) | |||
727 | const char *p; | 728 | const char *p; |
728 | char *ret; | 729 | char *ret; |
729 | int i; | 730 | int i; |
731 | Key *key; | ||
730 | 732 | ||
731 | buffer_init(&b); | 733 | buffer_init(&b); |
732 | for (i = 0; i < options.num_host_key_files; i++) { | 734 | for (i = 0; i < options.num_host_key_files; i++) { |
733 | Key *key = sensitive_data.host_keys[i]; | 735 | key = sensitive_data.host_keys[i]; |
734 | if (key == NULL) | 736 | if (key == NULL) |
735 | continue; | 737 | continue; |
736 | switch (key->type) { | 738 | switch (key->type) { |
@@ -742,6 +744,19 @@ list_hostkey_types(void) | |||
742 | buffer_append(&b, p, strlen(p)); | 744 | buffer_append(&b, p, strlen(p)); |
743 | break; | 745 | break; |
744 | } | 746 | } |
747 | /* If the private key has a cert peer, then list that too */ | ||
748 | key = sensitive_data.host_certificates[i]; | ||
749 | if (key == NULL) | ||
750 | continue; | ||
751 | switch (key->type) { | ||
752 | case KEY_RSA_CERT: | ||
753 | case KEY_DSA_CERT: | ||
754 | if (buffer_len(&b) > 0) | ||
755 | buffer_append(&b, ",", 1); | ||
756 | p = key_ssh_name(key); | ||
757 | buffer_append(&b, p, strlen(p)); | ||
758 | break; | ||
759 | } | ||
745 | } | 760 | } |
746 | buffer_append(&b, "\0", 1); | 761 | buffer_append(&b, "\0", 1); |
747 | ret = xstrdup(buffer_ptr(&b)); | 762 | ret = xstrdup(buffer_ptr(&b)); |
@@ -750,20 +765,37 @@ list_hostkey_types(void) | |||
750 | return ret; | 765 | return ret; |
751 | } | 766 | } |
752 | 767 | ||
753 | Key * | 768 | static Key * |
754 | get_hostkey_by_type(int type) | 769 | get_hostkey_by_type(int type, int need_private) |
755 | { | 770 | { |
756 | int i; | 771 | int i; |
772 | Key *key; | ||
757 | 773 | ||
758 | for (i = 0; i < options.num_host_key_files; i++) { | 774 | for (i = 0; i < options.num_host_key_files; i++) { |
759 | Key *key = sensitive_data.host_keys[i]; | 775 | if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) |
776 | key = sensitive_data.host_certificates[i]; | ||
777 | else | ||
778 | key = sensitive_data.host_keys[i]; | ||
760 | if (key != NULL && key->type == type) | 779 | if (key != NULL && key->type == type) |
761 | return key; | 780 | return need_private ? |
781 | sensitive_data.host_keys[i] : key; | ||
762 | } | 782 | } |
763 | return NULL; | 783 | return NULL; |
764 | } | 784 | } |
765 | 785 | ||
766 | Key * | 786 | Key * |
787 | get_hostkey_public_by_type(int type) | ||
788 | { | ||
789 | return get_hostkey_by_type(type, 0); | ||
790 | } | ||
791 | |||
792 | Key * | ||
793 | get_hostkey_private_by_type(int type) | ||
794 | { | ||
795 | return get_hostkey_by_type(type, 1); | ||
796 | } | ||
797 | |||
798 | Key * | ||
767 | get_hostkey_by_index(int ind) | 799 | get_hostkey_by_index(int ind) |
768 | { | 800 | { |
769 | if (ind < 0 || ind >= options.num_host_key_files) | 801 | if (ind < 0 || ind >= options.num_host_key_files) |
@@ -777,8 +809,13 @@ get_hostkey_index(Key *key) | |||
777 | int i; | 809 | int i; |
778 | 810 | ||
779 | for (i = 0; i < options.num_host_key_files; i++) { | 811 | for (i = 0; i < options.num_host_key_files; i++) { |
780 | if (key == sensitive_data.host_keys[i]) | 812 | if (key_is_cert(key)) { |
781 | return (i); | 813 | if (key == sensitive_data.host_certificates[i]) |
814 | return (i); | ||
815 | } else { | ||
816 | if (key == sensitive_data.host_keys[i]) | ||
817 | return (i); | ||
818 | } | ||
782 | } | 819 | } |
783 | return (-1); | 820 | return (-1); |
784 | } | 821 | } |
@@ -817,9 +854,9 @@ usage(void) | |||
817 | fprintf(stderr, "%s, %s\n", | 854 | fprintf(stderr, "%s, %s\n", |
818 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); | 855 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); |
819 | fprintf(stderr, | 856 | fprintf(stderr, |
820 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n" | 857 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" |
821 | " [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n" | 858 | " [-f config_file] [-g login_grace_time] [-h host_key_file]\n" |
822 | " [-o option] [-p port] [-u len]\n" | 859 | " [-k key_gen_time] [-o option] [-p port] [-u len]\n" |
823 | ); | 860 | ); |
824 | exit(1); | 861 | exit(1); |
825 | } | 862 | } |
@@ -915,31 +952,6 @@ recv_rexec_state(int fd, Buffer *conf) | |||
915 | debug3("%s: done", __func__); | 952 | debug3("%s: done", __func__); |
916 | } | 953 | } |
917 | 954 | ||
918 | #ifdef OOM_ADJUST | ||
919 | /* | ||
920 | * If requested in the environment, tell the Linux kernel's out-of-memory | ||
921 | * killer to avoid sshd. The old state will be restored when forking child | ||
922 | * processes. | ||
923 | */ | ||
924 | static void | ||
925 | oom_adjust_startup(void) | ||
926 | { | ||
927 | const char *oom_adj = getenv("SSHD_OOM_ADJUST"); | ||
928 | |||
929 | if (!oom_adj || !*oom_adj) | ||
930 | return; | ||
931 | oom_adj_get(oom_adj_save, sizeof(oom_adj_save)); | ||
932 | oom_adj_set(oom_adj); | ||
933 | } | ||
934 | |||
935 | static void | ||
936 | oom_restore(void) | ||
937 | { | ||
938 | if (oom_adj_save[0]) | ||
939 | oom_adj_set(oom_adj_save); | ||
940 | } | ||
941 | #endif | ||
942 | |||
943 | /* Accept a connection from inetd */ | 955 | /* Accept a connection from inetd */ |
944 | static void | 956 | static void |
945 | server_accept_inetd(int *sock_in, int *sock_out) | 957 | server_accept_inetd(int *sock_in, int *sock_out) |
@@ -1015,15 +1027,9 @@ server_listen(void) | |||
1015 | &on, sizeof(on)) == -1) | 1027 | &on, sizeof(on)) == -1) |
1016 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | 1028 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); |
1017 | 1029 | ||
1018 | #ifdef IPV6_V6ONLY | ||
1019 | /* Only communicate in IPv6 over AF_INET6 sockets. */ | 1030 | /* Only communicate in IPv6 over AF_INET6 sockets. */ |
1020 | if (ai->ai_family == AF_INET6) { | 1031 | if (ai->ai_family == AF_INET6) |
1021 | if (setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, | 1032 | sock_set_v6only(listen_sock); |
1022 | &on, sizeof(on)) == -1) | ||
1023 | error("setsockopt IPV6_V6ONLY: %s", | ||
1024 | strerror(errno)); | ||
1025 | } | ||
1026 | #endif | ||
1027 | 1033 | ||
1028 | debug("Bind to port %s on %s.", strport, ntop); | 1034 | debug("Bind to port %s on %s.", strport, ntop); |
1029 | 1035 | ||
@@ -1277,7 +1283,7 @@ main(int ac, char **av) | |||
1277 | { | 1283 | { |
1278 | extern char *optarg; | 1284 | extern char *optarg; |
1279 | extern int optind; | 1285 | extern int optind; |
1280 | int opt, i, on = 1; | 1286 | int opt, i, j, on = 1; |
1281 | int sock_in = -1, sock_out = -1, newsock = -1; | 1287 | int sock_in = -1, sock_out = -1, newsock = -1; |
1282 | const char *remote_ip; | 1288 | const char *remote_ip; |
1283 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; | 1289 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; |
@@ -1330,6 +1336,14 @@ main(int ac, char **av) | |||
1330 | case 'f': | 1336 | case 'f': |
1331 | config_file_name = optarg; | 1337 | config_file_name = optarg; |
1332 | break; | 1338 | break; |
1339 | case 'c': | ||
1340 | if (options.num_host_cert_files >= MAX_HOSTCERTS) { | ||
1341 | fprintf(stderr, "too many host certificates.\n"); | ||
1342 | exit(1); | ||
1343 | } | ||
1344 | options.host_cert_files[options.num_host_cert_files++] = | ||
1345 | derelativise_path(optarg); | ||
1346 | break; | ||
1333 | case 'd': | 1347 | case 'd': |
1334 | if (debug_flag == 0) { | 1348 | if (debug_flag == 0) { |
1335 | debug_flag = 1; | 1349 | debug_flag = 1; |
@@ -1397,7 +1411,8 @@ main(int ac, char **av) | |||
1397 | fprintf(stderr, "too many host keys.\n"); | 1411 | fprintf(stderr, "too many host keys.\n"); |
1398 | exit(1); | 1412 | exit(1); |
1399 | } | 1413 | } |
1400 | options.host_key_files[options.num_host_key_files++] = optarg; | 1414 | options.host_key_files[options.num_host_key_files++] = |
1415 | derelativise_path(optarg); | ||
1401 | break; | 1416 | break; |
1402 | case 't': | 1417 | case 't': |
1403 | test_flag = 1; | 1418 | test_flag = 1; |
@@ -1555,7 +1570,7 @@ main(int ac, char **av) | |||
1555 | sensitive_data.host_keys[i] = NULL; | 1570 | sensitive_data.host_keys[i] = NULL; |
1556 | continue; | 1571 | continue; |
1557 | } | 1572 | } |
1558 | if (reject_blacklisted_key(key, 1) == 1) { | 1573 | if (auth_key_is_revoked(key, 1)) { |
1559 | key_free(key); | 1574 | key_free(key); |
1560 | sensitive_data.host_keys[i] = NULL; | 1575 | sensitive_data.host_keys[i] = NULL; |
1561 | continue; | 1576 | continue; |
@@ -1589,6 +1604,46 @@ main(int ac, char **av) | |||
1589 | exit(1); | 1604 | exit(1); |
1590 | } | 1605 | } |
1591 | 1606 | ||
1607 | /* | ||
1608 | * Load certificates. They are stored in an array at identical | ||
1609 | * indices to the public keys that they relate to. | ||
1610 | */ | ||
1611 | sensitive_data.host_certificates = xcalloc(options.num_host_key_files, | ||
1612 | sizeof(Key *)); | ||
1613 | for (i = 0; i < options.num_host_key_files; i++) | ||
1614 | sensitive_data.host_certificates[i] = NULL; | ||
1615 | |||
1616 | for (i = 0; i < options.num_host_cert_files; i++) { | ||
1617 | key = key_load_public(options.host_cert_files[i], NULL); | ||
1618 | if (key == NULL) { | ||
1619 | error("Could not load host certificate: %s", | ||
1620 | options.host_cert_files[i]); | ||
1621 | continue; | ||
1622 | } | ||
1623 | if (!key_is_cert(key)) { | ||
1624 | error("Certificate file is not a certificate: %s", | ||
1625 | options.host_cert_files[i]); | ||
1626 | key_free(key); | ||
1627 | continue; | ||
1628 | } | ||
1629 | /* Find matching private key */ | ||
1630 | for (j = 0; j < options.num_host_key_files; j++) { | ||
1631 | if (key_equal_public(key, | ||
1632 | sensitive_data.host_keys[j])) { | ||
1633 | sensitive_data.host_certificates[j] = key; | ||
1634 | break; | ||
1635 | } | ||
1636 | } | ||
1637 | if (j >= options.num_host_key_files) { | ||
1638 | error("No matching private key for certificate: %s", | ||
1639 | options.host_cert_files[i]); | ||
1640 | key_free(key); | ||
1641 | continue; | ||
1642 | } | ||
1643 | sensitive_data.host_certificates[j] = key; | ||
1644 | debug("host certificate: #%d type %d %s", j, key->type, | ||
1645 | key_type(key)); | ||
1646 | } | ||
1592 | /* Check certain values for sanity. */ | 1647 | /* Check certain values for sanity. */ |
1593 | if (options.protocol & SSH_PROTO_1) { | 1648 | if (options.protocol & SSH_PROTO_1) { |
1594 | if (options.server_key_bits < 512 || | 1649 | if (options.server_key_bits < 512 || |
@@ -1707,15 +1762,11 @@ main(int ac, char **av) | |||
1707 | /* ignore SIGPIPE */ | 1762 | /* ignore SIGPIPE */ |
1708 | signal(SIGPIPE, SIG_IGN); | 1763 | signal(SIGPIPE, SIG_IGN); |
1709 | 1764 | ||
1710 | #ifdef OOM_ADJUST | ||
1711 | /* Adjust out-of-memory killer */ | ||
1712 | oom_adjust_startup(); | ||
1713 | #endif | ||
1714 | |||
1715 | /* Get a connection, either from inetd or a listening TCP socket */ | 1765 | /* Get a connection, either from inetd or a listening TCP socket */ |
1716 | if (inetd_flag) { | 1766 | if (inetd_flag) { |
1717 | server_accept_inetd(&sock_in, &sock_out); | 1767 | server_accept_inetd(&sock_in, &sock_out); |
1718 | } else { | 1768 | } else { |
1769 | platform_pre_listen(); | ||
1719 | server_listen(); | 1770 | server_listen(); |
1720 | 1771 | ||
1721 | if (options.protocol & SSH_PROTO_1) | 1772 | if (options.protocol & SSH_PROTO_1) |
@@ -1750,10 +1801,6 @@ main(int ac, char **av) | |||
1750 | /* This is the child processing a new connection. */ | 1801 | /* This is the child processing a new connection. */ |
1751 | setproctitle("%s", "[accepted]"); | 1802 | setproctitle("%s", "[accepted]"); |
1752 | 1803 | ||
1753 | #ifdef OOM_ADJUST | ||
1754 | oom_restore(); | ||
1755 | #endif | ||
1756 | |||
1757 | /* | 1804 | /* |
1758 | * Create a new session and process group since the 4.4BSD | 1805 | * Create a new session and process group since the 4.4BSD |
1759 | * setlogin() affects the entire process group. We don't | 1806 | * setlogin() affects the entire process group. We don't |
@@ -1809,6 +1856,10 @@ main(int ac, char **av) | |||
1809 | sock_in, sock_out, newsock, startup_pipe, config_s[0]); | 1856 | sock_in, sock_out, newsock, startup_pipe, config_s[0]); |
1810 | } | 1857 | } |
1811 | 1858 | ||
1859 | /* Executed child processes don't need these. */ | ||
1860 | fcntl(sock_out, F_SETFD, FD_CLOEXEC); | ||
1861 | fcntl(sock_in, F_SETFD, FD_CLOEXEC); | ||
1862 | |||
1812 | /* | 1863 | /* |
1813 | * Disable the key regeneration alarm. We will not regenerate the | 1864 | * Disable the key regeneration alarm. We will not regenerate the |
1814 | * key since we are no longer in a position to give it to anyone. We | 1865 | * key since we are no longer in a position to give it to anyone. We |
@@ -1960,6 +2011,7 @@ main(int ac, char **av) | |||
1960 | 2011 | ||
1961 | /* prepare buffer to collect messages to display to user after login */ | 2012 | /* prepare buffer to collect messages to display to user after login */ |
1962 | buffer_init(&loginmsg); | 2013 | buffer_init(&loginmsg); |
2014 | auth_debug_reset(); | ||
1963 | 2015 | ||
1964 | if (use_privsep) | 2016 | if (use_privsep) |
1965 | if (privsep_preauth(authctxt) == 1) | 2017 | if (privsep_preauth(authctxt) == 1) |
@@ -2365,7 +2417,8 @@ do_ssh2_kex(void) | |||
2365 | kex->server = 1; | 2417 | kex->server = 1; |
2366 | kex->client_version_string=client_version_string; | 2418 | kex->client_version_string=client_version_string; |
2367 | kex->server_version_string=server_version_string; | 2419 | kex->server_version_string=server_version_string; |
2368 | kex->load_host_key=&get_hostkey_by_type; | 2420 | kex->load_host_public_key=&get_hostkey_public_by_type; |
2421 | kex->load_host_private_key=&get_hostkey_private_by_type; | ||
2369 | kex->host_key_index=&get_hostkey_index; | 2422 | kex->host_key_index=&get_hostkey_index; |
2370 | 2423 | ||
2371 | xxx_kex = kex; | 2424 | xxx_kex = kex; |