summaryrefslogtreecommitdiff
path: root/sshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c137
1 files changed, 115 insertions, 22 deletions
diff --git a/sshd.c b/sshd.c
index 2b2cc81a5..eb48e791d 100644
--- a/sshd.c
+++ b/sshd.c
@@ -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
746Key * 767static Key *
747get_hostkey_by_type(int type) 768get_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
759Key * 785Key *
786get_hostkey_public_by_type(int type)
787{
788 return get_hostkey_by_type(type, 0);
789}
790
791Key *
792get_hostkey_private_by_type(int type)
793{
794 return get_hostkey_by_type(type, 1);
795}
796
797Key *
760get_hostkey_by_index(int ind) 798get_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;