summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2004-06-25 13:33:20 +1000
committerDarren Tucker <dtucker@zip.com.au>2004-06-25 13:33:20 +1000
commit645ab757bd58dc0c8e42b9886863ec95bf058c3e (patch)
tree86b28519830db5ac41a1975794524a7d0498b93d
parentb5bc1a6393ab0dce132a35711e779644c36a3ffa (diff)
- djm@cvs.openbsd.org 2004/06/24 19:30:54
[servconf.c servconf.h sshd.c] re-exec sshd on accept(); initial work, final debugging and ok markus@
-rw-r--r--ChangeLog8
-rw-r--r--servconf.c48
-rw-r--r--servconf.h8
-rw-r--r--sshd.c229
4 files changed, 261 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index 023fde0cd..4367699d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
120040625
2 - (dtucker) OpenBSD CVS Sync
3 - djm@cvs.openbsd.org 2004/06/24 19:30:54
4 [servconf.c servconf.h sshd.c]
5 re-exec sshd on accept(); initial work, final debugging and ok markus@
6
120040623 720040623
2 - (dtucker) [auth1.c] Ensure do_pam_account is called for Protocol 1 8 - (dtucker) [auth1.c] Ensure do_pam_account is called for Protocol 1
3 connections with empty passwords. Patch from davidwu at nbttech.com, 9 connections with empty passwords. Patch from davidwu at nbttech.com,
@@ -1399,4 +1405,4 @@
1399 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 1405 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
1400 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 1406 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
1401 1407
1402$Id: ChangeLog,v 1.3443 2004/06/23 14:34:53 dtucker Exp $ 1408$Id: ChangeLog,v 1.3444 2004/06/25 03:33:20 dtucker Exp $
diff --git a/servconf.c b/servconf.c
index ef8651651..ea67f6288 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12#include "includes.h" 12#include "includes.h"
13RCSID("$OpenBSD: servconf.c,v 1.133 2004/05/23 23:59:53 dtucker Exp $"); 13RCSID("$OpenBSD: servconf.c,v 1.134 2004/06/24 19:30:54 djm Exp $");
14 14
15#include "ssh.h" 15#include "ssh.h"
16#include "log.h" 16#include "log.h"
@@ -942,26 +942,50 @@ parse_flag:
942/* Reads the server configuration file. */ 942/* Reads the server configuration file. */
943 943
944void 944void
945read_server_config(ServerOptions *options, const char *filename) 945load_server_config(const char *filename, Buffer *conf)
946{ 946{
947 int linenum, bad_options = 0; 947 char line[1024], *cp;
948 char line[1024];
949 FILE *f; 948 FILE *f;
950 949
951 debug2("read_server_config: filename %s", filename); 950 debug2("%s: filename %s", __func__, filename);
952 f = fopen(filename, "r"); 951 if ((f = fopen(filename, "r")) == NULL) {
953 if (!f) {
954 perror(filename); 952 perror(filename);
955 exit(1); 953 exit(1);
956 } 954 }
957 linenum = 0; 955 buffer_clear(conf);
958 while (fgets(line, sizeof(line), f)) { 956 while (fgets(line, sizeof(line), f)) {
959 /* Update line number counter. */ 957 /*
960 linenum++; 958 * Trim out comments and strip whitespace
961 if (process_server_config_line(options, line, filename, linenum) != 0) 959 * NB - preserve newlines, they are needed to reproduce
962 bad_options++; 960 * line numbers later for error messages
961 */
962 if ((cp = strchr(line, '#')) != NULL)
963 memcpy(cp, "\n", 2);
964 cp = line + strspn(line, " \t\r");
965
966 buffer_append(conf, cp, strlen(cp));
963 } 967 }
968 buffer_append(conf, "\0", 1);
964 fclose(f); 969 fclose(f);
970 debug2("%s: done config len = %d", __func__, buffer_len(conf));
971}
972
973void
974parse_server_config(ServerOptions *options, const char *filename, Buffer *conf)
975{
976 int linenum, bad_options = 0;
977 char *cp, *cbuf;
978
979 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
980
981 cbuf = xstrdup(buffer_ptr(conf));
982 linenum = 0;
983 while((cp = strsep(&cbuf, "\n")) != NULL) {
984 if (process_server_config_line(options, cp, filename,
985 linenum++) != 0)
986 bad_options++;
987 }
988 free(cbuf);
965 if (bad_options > 0) 989 if (bad_options > 0)
966 fatal("%s: terminating, %d bad configuration options", 990 fatal("%s: terminating, %d bad configuration options",
967 filename, bad_options); 991 filename, bad_options);
diff --git a/servconf.h b/servconf.h
index 36d2e5ca6..ebd056814 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.69 2004/05/23 23:59:53 dtucker Exp $ */ 1/* $OpenBSD: servconf.h,v 1.70 2004/06/24 19:30:54 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -16,6 +16,8 @@
16#ifndef SERVCONF_H 16#ifndef SERVCONF_H
17#define SERVCONF_H 17#define SERVCONF_H
18 18
19#include "buffer.h"
20
19#define MAX_PORTS 256 /* Max # ports. */ 21#define MAX_PORTS 256 /* Max # ports. */
20 22
21#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ 23#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
@@ -134,9 +136,9 @@ typedef struct {
134} ServerOptions; 136} ServerOptions;
135 137
136void initialize_server_options(ServerOptions *); 138void initialize_server_options(ServerOptions *);
137void read_server_config(ServerOptions *, const char *);
138void fill_default_server_options(ServerOptions *); 139void fill_default_server_options(ServerOptions *);
139int process_server_config_line(ServerOptions *, char *, const char *, int); 140int process_server_config_line(ServerOptions *, char *, const char *, int);
140 141void load_server_config(const char *, Buffer *);
142void parse_server_config(ServerOptions *, const char *, Buffer *);
141 143
142#endif /* SERVCONF_H */ 144#endif /* SERVCONF_H */
diff --git a/sshd.c b/sshd.c
index 34379172f..98e90b5ac 100644
--- a/sshd.c
+++ b/sshd.c
@@ -42,7 +42,7 @@
42 */ 42 */
43 43
44#include "includes.h" 44#include "includes.h"
45RCSID("$OpenBSD: sshd.c,v 1.293 2004/06/14 01:44:39 djm Exp $"); 45RCSID("$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;
137char **saved_argv; 139char **saved_argv;
138int saved_argc; 140int saved_argc;
139 141
142/* re-exec */
143int rexeced_flag = 0;
144int rexec_flag = 1;
145int rexec_argc = 0;
146char **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
782static void
783send_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
824static void
825recv_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