diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 229 |
1 files changed, 213 insertions, 16 deletions
@@ -42,7 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include "includes.h" | 44 | #include "includes.h" |
45 | RCSID("$OpenBSD: sshd.c,v 1.293 2004/06/14 01:44:39 djm Exp $"); | 45 | RCSID("$OpenBSD: sshd.c,v 1.294 2004/06/24 19:30:54 djm Exp $"); |
46 | 46 | ||
47 | #include <openssl/dh.h> | 47 | #include <openssl/dh.h> |
48 | #include <openssl/bn.h> | 48 | #include <openssl/bn.h> |
@@ -65,6 +65,7 @@ RCSID("$OpenBSD: sshd.c,v 1.293 2004/06/14 01:44:39 djm Exp $"); | |||
65 | #include "uidswap.h" | 65 | #include "uidswap.h" |
66 | #include "compat.h" | 66 | #include "compat.h" |
67 | #include "buffer.h" | 67 | #include "buffer.h" |
68 | #include "bufaux.h" | ||
68 | #include "cipher.h" | 69 | #include "cipher.h" |
69 | #include "kex.h" | 70 | #include "kex.h" |
70 | #include "key.h" | 71 | #include "key.h" |
@@ -76,6 +77,7 @@ RCSID("$OpenBSD: sshd.c,v 1.293 2004/06/14 01:44:39 djm Exp $"); | |||
76 | #include "canohost.h" | 77 | #include "canohost.h" |
77 | #include "auth.h" | 78 | #include "auth.h" |
78 | #include "misc.h" | 79 | #include "misc.h" |
80 | #include "msg.h" | ||
79 | #include "dispatch.h" | 81 | #include "dispatch.h" |
80 | #include "channels.h" | 82 | #include "channels.h" |
81 | #include "session.h" | 83 | #include "session.h" |
@@ -137,6 +139,12 @@ int log_stderr = 0; | |||
137 | char **saved_argv; | 139 | char **saved_argv; |
138 | int saved_argc; | 140 | int saved_argc; |
139 | 141 | ||
142 | /* re-exec */ | ||
143 | int rexeced_flag = 0; | ||
144 | int rexec_flag = 1; | ||
145 | int rexec_argc = 0; | ||
146 | char **rexec_argv; | ||
147 | |||
140 | /* | 148 | /* |
141 | * The sockets that the server is listening; this is used in the SIGHUP | 149 | * The sockets that the server is listening; this is used in the SIGHUP |
142 | * signal handler. | 150 | * signal handler. |
@@ -771,6 +779,87 @@ usage(void) | |||
771 | exit(1); | 779 | exit(1); |
772 | } | 780 | } |
773 | 781 | ||
782 | static void | ||
783 | send_rexec_state(int fd, Buffer *conf) | ||
784 | { | ||
785 | Buffer m; | ||
786 | |||
787 | debug3("%s: entering fd = %d config len %d", __func__, fd, | ||
788 | buffer_len(conf)); | ||
789 | |||
790 | /* | ||
791 | * Protocol from reexec master to child: | ||
792 | * string configuration | ||
793 | * u_int ephemeral_key_follows | ||
794 | * bignum e (only if ephemeral_key_follows == 1) | ||
795 | * bignum n " | ||
796 | * bignum d " | ||
797 | * bignum iqmp " | ||
798 | * bignum p " | ||
799 | * bignum q " | ||
800 | */ | ||
801 | buffer_init(&m); | ||
802 | buffer_put_cstring(&m, buffer_ptr(conf)); | ||
803 | |||
804 | if (sensitive_data.server_key != NULL && | ||
805 | sensitive_data.server_key->type == KEY_RSA1) { | ||
806 | buffer_put_int(&m, 1); | ||
807 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->e); | ||
808 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->n); | ||
809 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->d); | ||
810 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp); | ||
811 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->p); | ||
812 | buffer_put_bignum(&m, sensitive_data.server_key->rsa->q); | ||
813 | } else | ||
814 | buffer_put_int(&m, 0); | ||
815 | |||
816 | if (ssh_msg_send(fd, 0, &m) == -1) | ||
817 | fatal("%s: ssh_msg_send failed", __func__); | ||
818 | |||
819 | buffer_free(&m); | ||
820 | |||
821 | debug3("%s: done", __func__); | ||
822 | } | ||
823 | |||
824 | static void | ||
825 | recv_rexec_state(int fd, Buffer *conf) | ||
826 | { | ||
827 | Buffer m; | ||
828 | char *cp; | ||
829 | u_int len; | ||
830 | |||
831 | debug3("%s: entering fd = %d", __func__, fd); | ||
832 | |||
833 | buffer_init(&m); | ||
834 | |||
835 | if (ssh_msg_recv(fd, &m) == -1) | ||
836 | fatal("%s: ssh_msg_recv failed", __func__); | ||
837 | if (buffer_get_char(&m) != 0) | ||
838 | fatal("%s: rexec version mismatch", __func__); | ||
839 | |||
840 | cp = buffer_get_string(&m, &len); | ||
841 | if (conf != NULL) | ||
842 | buffer_append(conf, cp, len + 1); | ||
843 | xfree(cp); | ||
844 | |||
845 | if (buffer_get_int(&m)) { | ||
846 | if (sensitive_data.server_key != NULL) | ||
847 | key_free(sensitive_data.server_key); | ||
848 | sensitive_data.server_key = key_new_private(KEY_RSA1); | ||
849 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->e); | ||
850 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->n); | ||
851 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->d); | ||
852 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); | ||
853 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); | ||
854 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); | ||
855 | rsa_generate_additional_parameters( | ||
856 | sensitive_data.server_key->rsa); | ||
857 | } | ||
858 | buffer_free(&m); | ||
859 | |||
860 | debug3("%s: done", __func__); | ||
861 | } | ||
862 | |||
774 | /* | 863 | /* |
775 | * Main program for the daemon. | 864 | * Main program for the daemon. |
776 | */ | 865 | */ |
@@ -791,11 +880,12 @@ main(int ac, char **av) | |||
791 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 880 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
792 | char *line; | 881 | char *line; |
793 | int listen_sock, maxfd; | 882 | int listen_sock, maxfd; |
794 | int startup_p[2]; | 883 | int startup_p[2], config_s[2]; |
795 | int startups = 0; | 884 | int startups = 0; |
796 | Key *key; | 885 | Key *key; |
797 | Authctxt *authctxt; | 886 | Authctxt *authctxt; |
798 | int ret, key_used = 0; | 887 | int ret, key_used = 0; |
888 | Buffer cfg; | ||
799 | 889 | ||
800 | #ifdef HAVE_SECUREWARE | 890 | #ifdef HAVE_SECUREWARE |
801 | (void)set_auth_parameters(ac, av); | 891 | (void)set_auth_parameters(ac, av); |
@@ -823,7 +913,7 @@ main(int ac, char **av) | |||
823 | initialize_server_options(&options); | 913 | initialize_server_options(&options); |
824 | 914 | ||
825 | /* Parse command-line arguments. */ | 915 | /* Parse command-line arguments. */ |
826 | while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqtQ46")) != -1) { | 916 | while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) { |
827 | switch (opt) { | 917 | switch (opt) { |
828 | case '4': | 918 | case '4': |
829 | IPv4or6 = AF_INET; | 919 | IPv4or6 = AF_INET; |
@@ -850,6 +940,13 @@ main(int ac, char **av) | |||
850 | case 'i': | 940 | case 'i': |
851 | inetd_flag = 1; | 941 | inetd_flag = 1; |
852 | break; | 942 | break; |
943 | case 'r': | ||
944 | rexec_flag = 0; | ||
945 | break; | ||
946 | case 'R': | ||
947 | rexeced_flag = 1; | ||
948 | inetd_flag = 1; | ||
949 | break; | ||
853 | case 'Q': | 950 | case 'Q': |
854 | /* ignored */ | 951 | /* ignored */ |
855 | break; | 952 | break; |
@@ -913,6 +1010,13 @@ main(int ac, char **av) | |||
913 | break; | 1010 | break; |
914 | } | 1011 | } |
915 | } | 1012 | } |
1013 | if (rexeced_flag || inetd_flag) | ||
1014 | rexec_flag = 0; | ||
1015 | if (rexec_flag && (av[0] == NULL || *av[0] != '/')) | ||
1016 | fatal("sshd re-exec requires execution with an absolute path"); | ||
1017 | if (rexeced_flag) | ||
1018 | closefrom(STDERR_FILENO + 3); | ||
1019 | |||
916 | SSLeay_add_all_algorithms(); | 1020 | SSLeay_add_all_algorithms(); |
917 | channel_set_af(IPv4or6); | 1021 | channel_set_af(IPv4or6); |
918 | 1022 | ||
@@ -943,8 +1047,23 @@ main(int ac, char **av) | |||
943 | 1047 | ||
944 | seed_rng(); | 1048 | seed_rng(); |
945 | 1049 | ||
946 | /* Read server configuration options from the configuration file. */ | 1050 | sensitive_data.server_key = NULL; |
947 | read_server_config(&options, config_file_name); | 1051 | sensitive_data.ssh1_host_key = NULL; |
1052 | sensitive_data.have_ssh1_key = 0; | ||
1053 | sensitive_data.have_ssh2_key = 0; | ||
1054 | |||
1055 | /* Fetch our configuration */ | ||
1056 | buffer_init(&cfg); | ||
1057 | if (rexeced_flag) | ||
1058 | recv_rexec_state(STDERR_FILENO + 2, &cfg); | ||
1059 | else | ||
1060 | load_server_config(config_file_name, &cfg); | ||
1061 | |||
1062 | parse_server_config(&options, | ||
1063 | rexeced_flag ? "rexec" : config_file_name, &cfg); | ||
1064 | |||
1065 | if (!rexec_flag) | ||
1066 | buffer_free(&cfg); | ||
948 | 1067 | ||
949 | /* Fill in default values for those options not explicitly set. */ | 1068 | /* Fill in default values for those options not explicitly set. */ |
950 | fill_default_server_options(&options); | 1069 | fill_default_server_options(&options); |
@@ -962,10 +1081,6 @@ main(int ac, char **av) | |||
962 | sizeof(Key *)); | 1081 | sizeof(Key *)); |
963 | for (i = 0; i < options.num_host_key_files; i++) | 1082 | for (i = 0; i < options.num_host_key_files; i++) |
964 | sensitive_data.host_keys[i] = NULL; | 1083 | sensitive_data.host_keys[i] = NULL; |
965 | sensitive_data.server_key = NULL; | ||
966 | sensitive_data.ssh1_host_key = NULL; | ||
967 | sensitive_data.have_ssh1_key = 0; | ||
968 | sensitive_data.have_ssh2_key = 0; | ||
969 | 1084 | ||
970 | for (i = 0; i < options.num_host_key_files; i++) { | 1085 | for (i = 0; i < options.num_host_key_files; i++) { |
971 | key = key_load_private(options.host_key_files[i], "", NULL); | 1086 | key = key_load_private(options.host_key_files[i], "", NULL); |
@@ -1064,6 +1179,16 @@ main(int ac, char **av) | |||
1064 | if (setgroups(0, NULL) < 0) | 1179 | if (setgroups(0, NULL) < 0) |
1065 | debug("setgroups() failed: %.200s", strerror(errno)); | 1180 | debug("setgroups() failed: %.200s", strerror(errno)); |
1066 | 1181 | ||
1182 | if (rexec_flag) { | ||
1183 | rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2)); | ||
1184 | for (i = 0; i < rexec_argc; i++) { | ||
1185 | debug("rexec_argv[%d]='%s'", i, saved_argv[i]); | ||
1186 | rexec_argv[i] = saved_argv[i]; | ||
1187 | } | ||
1188 | rexec_argv[rexec_argc] = "-R"; | ||
1189 | rexec_argv[rexec_argc + 1] = NULL; | ||
1190 | } | ||
1191 | |||
1067 | /* Initialize the log (it is reinitialized below in case we forked). */ | 1192 | /* Initialize the log (it is reinitialized below in case we forked). */ |
1068 | if (debug_flag && !inetd_flag) | 1193 | if (debug_flag && !inetd_flag) |
1069 | log_stderr = 1; | 1194 | log_stderr = 1; |
@@ -1105,19 +1230,34 @@ main(int ac, char **av) | |||
1105 | 1230 | ||
1106 | /* Start listening for a socket, unless started from inetd. */ | 1231 | /* Start listening for a socket, unless started from inetd. */ |
1107 | if (inetd_flag) { | 1232 | if (inetd_flag) { |
1108 | int s1; | 1233 | int fd; |
1109 | s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ | 1234 | |
1110 | dup(s1); | ||
1111 | sock_in = dup(0); | ||
1112 | sock_out = dup(1); | ||
1113 | startup_pipe = -1; | 1235 | startup_pipe = -1; |
1236 | if (rexeced_flag) { | ||
1237 | close(STDERR_FILENO + 2); | ||
1238 | sock_in = sock_out = dup(STDIN_FILENO); | ||
1239 | if (!debug_flag) { | ||
1240 | startup_pipe = dup(STDERR_FILENO + 1); | ||
1241 | close(STDERR_FILENO + 1); | ||
1242 | } | ||
1243 | } else { | ||
1244 | sock_in = dup(STDIN_FILENO); | ||
1245 | sock_out = dup(STDOUT_FILENO); | ||
1246 | } | ||
1114 | /* | 1247 | /* |
1115 | * We intentionally do not close the descriptors 0, 1, and 2 | 1248 | * We intentionally do not close the descriptors 0, 1, and 2 |
1116 | * as our code for setting the descriptors won\'t work if | 1249 | * as our code for setting the descriptors won't work if |
1117 | * ttyfd happens to be one of those. | 1250 | * ttyfd happens to be one of those. |
1118 | */ | 1251 | */ |
1252 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
1253 | dup2(fd, STDIN_FILENO); | ||
1254 | dup2(fd, STDOUT_FILENO); | ||
1255 | if (fd > STDOUT_FILENO) | ||
1256 | close(fd); | ||
1257 | } | ||
1119 | debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); | 1258 | debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); |
1120 | if (options.protocol & SSH_PROTO_1) | 1259 | if ((options.protocol & SSH_PROTO_1) && |
1260 | sensitive_data.server_key == NULL) | ||
1121 | generate_ephemeral_server_key(); | 1261 | generate_ephemeral_server_key(); |
1122 | } else { | 1262 | } else { |
1123 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | 1263 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { |
@@ -1297,6 +1437,16 @@ main(int ac, char **av) | |||
1297 | continue; | 1437 | continue; |
1298 | } | 1438 | } |
1299 | 1439 | ||
1440 | if (rexec_flag && socketpair(AF_UNIX, | ||
1441 | SOCK_STREAM, 0, config_s) == -1) { | ||
1442 | error("reexec socketpair: %s", | ||
1443 | strerror(errno)); | ||
1444 | close(newsock); | ||
1445 | close(startup_p[0]); | ||
1446 | close(startup_p[1]); | ||
1447 | continue; | ||
1448 | } | ||
1449 | |||
1300 | for (j = 0; j < options.max_startups; j++) | 1450 | for (j = 0; j < options.max_startups; j++) |
1301 | if (startup_pipes[j] == -1) { | 1451 | if (startup_pipes[j] == -1) { |
1302 | startup_pipes[j] = startup_p[0]; | 1452 | startup_pipes[j] = startup_p[0]; |
@@ -1320,8 +1470,15 @@ main(int ac, char **av) | |||
1320 | close_listen_socks(); | 1470 | close_listen_socks(); |
1321 | sock_in = newsock; | 1471 | sock_in = newsock; |
1322 | sock_out = newsock; | 1472 | sock_out = newsock; |
1473 | close(startup_p[0]); | ||
1474 | close(startup_p[1]); | ||
1323 | startup_pipe = -1; | 1475 | startup_pipe = -1; |
1324 | pid = getpid(); | 1476 | pid = getpid(); |
1477 | if (rexec_flag) { | ||
1478 | send_rexec_state(config_s[0], | ||
1479 | &cfg); | ||
1480 | close(config_s[0]); | ||
1481 | } | ||
1325 | break; | 1482 | break; |
1326 | } else { | 1483 | } else { |
1327 | /* | 1484 | /* |
@@ -1355,6 +1512,12 @@ main(int ac, char **av) | |||
1355 | 1512 | ||
1356 | close(startup_p[1]); | 1513 | close(startup_p[1]); |
1357 | 1514 | ||
1515 | if (rexec_flag) { | ||
1516 | send_rexec_state(config_s[0], &cfg); | ||
1517 | close(config_s[0]); | ||
1518 | close(config_s[1]); | ||
1519 | } | ||
1520 | |||
1358 | /* Mark that the key has been used (it was "given" to the child). */ | 1521 | /* Mark that the key has been used (it was "given" to the child). */ |
1359 | if ((options.protocol & SSH_PROTO_1) && | 1522 | if ((options.protocol & SSH_PROTO_1) && |
1360 | key_used == 0) { | 1523 | key_used == 0) { |
@@ -1378,6 +1541,40 @@ main(int ac, char **av) | |||
1378 | /* This is the child processing a new connection. */ | 1541 | /* This is the child processing a new connection. */ |
1379 | setproctitle("%s", "[accepted]"); | 1542 | setproctitle("%s", "[accepted]"); |
1380 | 1543 | ||
1544 | if (rexec_flag) { | ||
1545 | int fd; | ||
1546 | |||
1547 | debug("rexec newsock %d pipe %d sock %d", newsock, | ||
1548 | startup_pipe, config_s[0]); | ||
1549 | dup2(newsock, STDIN_FILENO); | ||
1550 | dup2(STDIN_FILENO, STDOUT_FILENO); | ||
1551 | if (startup_pipe == -1) | ||
1552 | close(STDERR_FILENO + 1); | ||
1553 | else | ||
1554 | dup2(startup_pipe, STDERR_FILENO + 1); | ||
1555 | |||
1556 | dup2(config_s[1], STDERR_FILENO + 2); | ||
1557 | close(config_s[1]); | ||
1558 | execv(rexec_argv[0], rexec_argv); | ||
1559 | |||
1560 | /* Reexec has failed, fall back and continue */ | ||
1561 | error("rexec of %s failed: %s", rexec_argv[0], strerror(errno)); | ||
1562 | recv_rexec_state(STDERR_FILENO + 2, NULL); | ||
1563 | log_init(__progname, options.log_level, | ||
1564 | options.log_facility, log_stderr); | ||
1565 | |||
1566 | /* Clean up fds */ | ||
1567 | close(config_s[1]); | ||
1568 | close(STDERR_FILENO + 1); | ||
1569 | close(STDERR_FILENO + 2); | ||
1570 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
1571 | dup2(fd, STDIN_FILENO); | ||
1572 | dup2(fd, STDOUT_FILENO); | ||
1573 | if (fd > STDERR_FILENO) | ||
1574 | close(fd); | ||
1575 | } | ||
1576 | } | ||
1577 | |||
1381 | /* | 1578 | /* |
1382 | * Create a new session and process group since the 4.4BSD | 1579 | * Create a new session and process group since the 4.4BSD |
1383 | * setlogin() affects the entire process group. We don't | 1580 | * setlogin() affects the entire process group. We don't |