diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 137 |
1 files changed, 115 insertions, 22 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]; |
@@ -313,6 +314,7 @@ sighup_restart(void) | |||
313 | close_listen_socks(); | 314 | close_listen_socks(); |
314 | close_startup_pipes(); | 315 | close_startup_pipes(); |
315 | alarm(0); /* alarm timer persists across exec */ | 316 | alarm(0); /* alarm timer persists across exec */ |
317 | signal(SIGHUP, SIG_IGN); /* will be restored after exec */ | ||
316 | execv(saved_argv[0], saved_argv); | 318 | execv(saved_argv[0], saved_argv); |
317 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], | 319 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], |
318 | strerror(errno)); | 320 | strerror(errno)); |
@@ -548,6 +550,10 @@ destroy_sensitive_data(void) | |||
548 | key_free(sensitive_data.host_keys[i]); | 550 | key_free(sensitive_data.host_keys[i]); |
549 | sensitive_data.host_keys[i] = NULL; | 551 | sensitive_data.host_keys[i] = NULL; |
550 | } | 552 | } |
553 | if (sensitive_data.host_certificates[i]) { | ||
554 | key_free(sensitive_data.host_certificates[i]); | ||
555 | sensitive_data.host_certificates[i] = NULL; | ||
556 | } | ||
551 | } | 557 | } |
552 | sensitive_data.ssh1_host_key = NULL; | 558 | sensitive_data.ssh1_host_key = NULL; |
553 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); | 559 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); |
@@ -574,6 +580,7 @@ demote_sensitive_data(void) | |||
574 | if (tmp->type == KEY_RSA1) | 580 | if (tmp->type == KEY_RSA1) |
575 | sensitive_data.ssh1_host_key = tmp; | 581 | sensitive_data.ssh1_host_key = tmp; |
576 | } | 582 | } |
583 | /* Certs do not need demotion */ | ||
577 | } | 584 | } |
578 | 585 | ||
579 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ | 586 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ |
@@ -720,10 +727,11 @@ list_hostkey_types(void) | |||
720 | const char *p; | 727 | const char *p; |
721 | char *ret; | 728 | char *ret; |
722 | int i; | 729 | int i; |
730 | Key *key; | ||
723 | 731 | ||
724 | buffer_init(&b); | 732 | buffer_init(&b); |
725 | for (i = 0; i < options.num_host_key_files; i++) { | 733 | for (i = 0; i < options.num_host_key_files; i++) { |
726 | Key *key = sensitive_data.host_keys[i]; | 734 | key = sensitive_data.host_keys[i]; |
727 | if (key == NULL) | 735 | if (key == NULL) |
728 | continue; | 736 | continue; |
729 | switch (key->type) { | 737 | switch (key->type) { |
@@ -735,6 +743,19 @@ list_hostkey_types(void) | |||
735 | buffer_append(&b, p, strlen(p)); | 743 | buffer_append(&b, p, strlen(p)); |
736 | break; | 744 | break; |
737 | } | 745 | } |
746 | /* If the private key has a cert peer, then list that too */ | ||
747 | key = sensitive_data.host_certificates[i]; | ||
748 | if (key == NULL) | ||
749 | continue; | ||
750 | switch (key->type) { | ||
751 | case KEY_RSA_CERT: | ||
752 | case KEY_DSA_CERT: | ||
753 | if (buffer_len(&b) > 0) | ||
754 | buffer_append(&b, ",", 1); | ||
755 | p = key_ssh_name(key); | ||
756 | buffer_append(&b, p, strlen(p)); | ||
757 | break; | ||
758 | } | ||
738 | } | 759 | } |
739 | buffer_append(&b, "\0", 1); | 760 | buffer_append(&b, "\0", 1); |
740 | ret = xstrdup(buffer_ptr(&b)); | 761 | ret = xstrdup(buffer_ptr(&b)); |
@@ -743,20 +764,37 @@ list_hostkey_types(void) | |||
743 | return ret; | 764 | return ret; |
744 | } | 765 | } |
745 | 766 | ||
746 | Key * | 767 | static Key * |
747 | get_hostkey_by_type(int type) | 768 | get_hostkey_by_type(int type, int need_private) |
748 | { | 769 | { |
749 | int i; | 770 | int i; |
771 | Key *key; | ||
750 | 772 | ||
751 | for (i = 0; i < options.num_host_key_files; i++) { | 773 | for (i = 0; i < options.num_host_key_files; i++) { |
752 | Key *key = sensitive_data.host_keys[i]; | 774 | if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) |
775 | key = sensitive_data.host_certificates[i]; | ||
776 | else | ||
777 | key = sensitive_data.host_keys[i]; | ||
753 | if (key != NULL && key->type == type) | 778 | if (key != NULL && key->type == type) |
754 | return key; | 779 | return need_private ? |
780 | sensitive_data.host_keys[i] : key; | ||
755 | } | 781 | } |
756 | return NULL; | 782 | return NULL; |
757 | } | 783 | } |
758 | 784 | ||
759 | Key * | 785 | Key * |
786 | get_hostkey_public_by_type(int type) | ||
787 | { | ||
788 | return get_hostkey_by_type(type, 0); | ||
789 | } | ||
790 | |||
791 | Key * | ||
792 | get_hostkey_private_by_type(int type) | ||
793 | { | ||
794 | return get_hostkey_by_type(type, 1); | ||
795 | } | ||
796 | |||
797 | Key * | ||
760 | get_hostkey_by_index(int ind) | 798 | get_hostkey_by_index(int ind) |
761 | { | 799 | { |
762 | if (ind < 0 || ind >= options.num_host_key_files) | 800 | if (ind < 0 || ind >= options.num_host_key_files) |
@@ -770,8 +808,13 @@ get_hostkey_index(Key *key) | |||
770 | int i; | 808 | int i; |
771 | 809 | ||
772 | for (i = 0; i < options.num_host_key_files; i++) { | 810 | for (i = 0; i < options.num_host_key_files; i++) { |
773 | if (key == sensitive_data.host_keys[i]) | 811 | if (key_is_cert(key)) { |
774 | return (i); | 812 | if (key == sensitive_data.host_certificates[i]) |
813 | return (i); | ||
814 | } else { | ||
815 | if (key == sensitive_data.host_keys[i]) | ||
816 | return (i); | ||
817 | } | ||
775 | } | 818 | } |
776 | return (-1); | 819 | return (-1); |
777 | } | 820 | } |
@@ -810,9 +853,9 @@ usage(void) | |||
810 | fprintf(stderr, "%s, %s\n", | 853 | fprintf(stderr, "%s, %s\n", |
811 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); | 854 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); |
812 | fprintf(stderr, | 855 | fprintf(stderr, |
813 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n" | 856 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" |
814 | " [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n" | 857 | " [-f config_file] [-g login_grace_time] [-h host_key_file]\n" |
815 | " [-o option] [-p port] [-u len]\n" | 858 | " [-k key_gen_time] [-o option] [-p port] [-u len]\n" |
816 | ); | 859 | ); |
817 | exit(1); | 860 | exit(1); |
818 | } | 861 | } |
@@ -983,15 +1026,9 @@ server_listen(void) | |||
983 | &on, sizeof(on)) == -1) | 1026 | &on, sizeof(on)) == -1) |
984 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | 1027 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); |
985 | 1028 | ||
986 | #ifdef IPV6_V6ONLY | ||
987 | /* Only communicate in IPv6 over AF_INET6 sockets. */ | 1029 | /* Only communicate in IPv6 over AF_INET6 sockets. */ |
988 | if (ai->ai_family == AF_INET6) { | 1030 | if (ai->ai_family == AF_INET6) |
989 | if (setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, | 1031 | sock_set_v6only(listen_sock); |
990 | &on, sizeof(on)) == -1) | ||
991 | error("setsockopt IPV6_V6ONLY: %s", | ||
992 | strerror(errno)); | ||
993 | } | ||
994 | #endif | ||
995 | 1032 | ||
996 | debug("Bind to port %s on %s.", strport, ntop); | 1033 | debug("Bind to port %s on %s.", strport, ntop); |
997 | 1034 | ||
@@ -1245,7 +1282,7 @@ main(int ac, char **av) | |||
1245 | { | 1282 | { |
1246 | extern char *optarg; | 1283 | extern char *optarg; |
1247 | extern int optind; | 1284 | extern int optind; |
1248 | int opt, i, on = 1; | 1285 | int opt, i, j, on = 1; |
1249 | int sock_in = -1, sock_out = -1, newsock = -1; | 1286 | int sock_in = -1, sock_out = -1, newsock = -1; |
1250 | const char *remote_ip; | 1287 | const char *remote_ip; |
1251 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; | 1288 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; |
@@ -1298,6 +1335,14 @@ main(int ac, char **av) | |||
1298 | case 'f': | 1335 | case 'f': |
1299 | config_file_name = optarg; | 1336 | config_file_name = optarg; |
1300 | break; | 1337 | break; |
1338 | case 'c': | ||
1339 | if (options.num_host_cert_files >= MAX_HOSTCERTS) { | ||
1340 | fprintf(stderr, "too many host certificates.\n"); | ||
1341 | exit(1); | ||
1342 | } | ||
1343 | options.host_cert_files[options.num_host_cert_files++] = | ||
1344 | derelativise_path(optarg); | ||
1345 | break; | ||
1301 | case 'd': | 1346 | case 'd': |
1302 | if (debug_flag == 0) { | 1347 | if (debug_flag == 0) { |
1303 | debug_flag = 1; | 1348 | debug_flag = 1; |
@@ -1360,7 +1405,8 @@ main(int ac, char **av) | |||
1360 | fprintf(stderr, "too many host keys.\n"); | 1405 | fprintf(stderr, "too many host keys.\n"); |
1361 | exit(1); | 1406 | exit(1); |
1362 | } | 1407 | } |
1363 | options.host_key_files[options.num_host_key_files++] = optarg; | 1408 | options.host_key_files[options.num_host_key_files++] = |
1409 | derelativise_path(optarg); | ||
1364 | break; | 1410 | break; |
1365 | case 't': | 1411 | case 't': |
1366 | test_flag = 1; | 1412 | test_flag = 1; |
@@ -1547,6 +1593,46 @@ main(int ac, char **av) | |||
1547 | exit(1); | 1593 | exit(1); |
1548 | } | 1594 | } |
1549 | 1595 | ||
1596 | /* | ||
1597 | * Load certificates. They are stored in an array at identical | ||
1598 | * indices to the public keys that they relate to. | ||
1599 | */ | ||
1600 | sensitive_data.host_certificates = xcalloc(options.num_host_key_files, | ||
1601 | sizeof(Key *)); | ||
1602 | for (i = 0; i < options.num_host_key_files; i++) | ||
1603 | sensitive_data.host_certificates[i] = NULL; | ||
1604 | |||
1605 | for (i = 0; i < options.num_host_cert_files; i++) { | ||
1606 | key = key_load_public(options.host_cert_files[i], NULL); | ||
1607 | if (key == NULL) { | ||
1608 | error("Could not load host certificate: %s", | ||
1609 | options.host_cert_files[i]); | ||
1610 | continue; | ||
1611 | } | ||
1612 | if (!key_is_cert(key)) { | ||
1613 | error("Certificate file is not a certificate: %s", | ||
1614 | options.host_cert_files[i]); | ||
1615 | key_free(key); | ||
1616 | continue; | ||
1617 | } | ||
1618 | /* Find matching private key */ | ||
1619 | for (j = 0; j < options.num_host_key_files; j++) { | ||
1620 | if (key_equal_public(key, | ||
1621 | sensitive_data.host_keys[j])) { | ||
1622 | sensitive_data.host_certificates[j] = key; | ||
1623 | break; | ||
1624 | } | ||
1625 | } | ||
1626 | if (j >= options.num_host_key_files) { | ||
1627 | error("No matching private key for certificate: %s", | ||
1628 | options.host_cert_files[i]); | ||
1629 | key_free(key); | ||
1630 | continue; | ||
1631 | } | ||
1632 | sensitive_data.host_certificates[j] = key; | ||
1633 | debug("host certificate: #%d type %d %s", j, key->type, | ||
1634 | key_type(key)); | ||
1635 | } | ||
1550 | /* Check certain values for sanity. */ | 1636 | /* Check certain values for sanity. */ |
1551 | if (options.protocol & SSH_PROTO_1) { | 1637 | if (options.protocol & SSH_PROTO_1) { |
1552 | if (options.server_key_bits < 512 || | 1638 | if (options.server_key_bits < 512 || |
@@ -1669,6 +1755,7 @@ main(int ac, char **av) | |||
1669 | if (inetd_flag) { | 1755 | if (inetd_flag) { |
1670 | server_accept_inetd(&sock_in, &sock_out); | 1756 | server_accept_inetd(&sock_in, &sock_out); |
1671 | } else { | 1757 | } else { |
1758 | platform_pre_listen(); | ||
1672 | server_listen(); | 1759 | server_listen(); |
1673 | 1760 | ||
1674 | if (options.protocol & SSH_PROTO_1) | 1761 | if (options.protocol & SSH_PROTO_1) |
@@ -1758,6 +1845,10 @@ main(int ac, char **av) | |||
1758 | sock_in, sock_out, newsock, startup_pipe, config_s[0]); | 1845 | sock_in, sock_out, newsock, startup_pipe, config_s[0]); |
1759 | } | 1846 | } |
1760 | 1847 | ||
1848 | /* Executed child processes don't need these. */ | ||
1849 | fcntl(sock_out, F_SETFD, FD_CLOEXEC); | ||
1850 | fcntl(sock_in, F_SETFD, FD_CLOEXEC); | ||
1851 | |||
1761 | /* | 1852 | /* |
1762 | * Disable the key regeneration alarm. We will not regenerate the | 1853 | * Disable the key regeneration alarm. We will not regenerate the |
1763 | * key since we are no longer in a position to give it to anyone. We | 1854 | * key since we are no longer in a position to give it to anyone. We |
@@ -1909,6 +2000,7 @@ main(int ac, char **av) | |||
1909 | 2000 | ||
1910 | /* prepare buffer to collect messages to display to user after login */ | 2001 | /* prepare buffer to collect messages to display to user after login */ |
1911 | buffer_init(&loginmsg); | 2002 | buffer_init(&loginmsg); |
2003 | auth_debug_reset(); | ||
1912 | 2004 | ||
1913 | if (use_privsep) | 2005 | if (use_privsep) |
1914 | if (privsep_preauth(authctxt) == 1) | 2006 | if (privsep_preauth(authctxt) == 1) |
@@ -2314,7 +2406,8 @@ do_ssh2_kex(void) | |||
2314 | kex->server = 1; | 2406 | kex->server = 1; |
2315 | kex->client_version_string=client_version_string; | 2407 | kex->client_version_string=client_version_string; |
2316 | kex->server_version_string=server_version_string; | 2408 | kex->server_version_string=server_version_string; |
2317 | kex->load_host_key=&get_hostkey_by_type; | 2409 | kex->load_host_public_key=&get_hostkey_public_by_type; |
2410 | kex->load_host_private_key=&get_hostkey_private_by_type; | ||
2318 | kex->host_key_index=&get_hostkey_index; | 2411 | kex->host_key_index=&get_hostkey_index; |
2319 | 2412 | ||
2320 | xxx_kex = kex; | 2413 | xxx_kex = kex; |