aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/sshd.c
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2004-10-28 16:11:31 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2004-10-28 16:11:31 +0000
commit21e764df0c8084af2d7d6f5ecdaa136ad81246ed (patch)
tree2b93d7eeb78a97c2cc9e93d61346f39150ed165f /crypto/openssh/sshd.c
parent5ba618aa27e6a84eb699b91af11a162d24082f30 (diff)
downloadsrc-21e764df0c8084af2d7d6f5ecdaa136ad81246ed.tar.gz
src-21e764df0c8084af2d7d6f5ecdaa136ad81246ed.zip
Resolve conflicts
Notes
Notes: svn path=/head/; revision=137019
Diffstat (limited to 'crypto/openssh/sshd.c')
-rw-r--r--crypto/openssh/sshd.c279
1 files changed, 246 insertions, 33 deletions
diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c
index 22c2e3d0a535..0e5dbf2b98ba 100644
--- a/crypto/openssh/sshd.c
+++ b/crypto/openssh/sshd.c
@@ -42,8 +42,8 @@
*/
#include "includes.h"
+RCSID("$OpenBSD: sshd.c,v 1.301 2004/08/11 11:50:09 dtucker Exp $");
RCSID("$FreeBSD$");
-RCSID("$OpenBSD: sshd.c,v 1.286 2004/02/23 12:02:33 markus Exp $");
#include <openssl/dh.h>
#include <openssl/bn.h>
@@ -65,12 +65,12 @@ RCSID("$OpenBSD: sshd.c,v 1.286 2004/02/23 12:02:33 markus Exp $");
#include "rsa.h"
#include "sshpty.h"
#include "packet.h"
-#include "mpaux.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "compat.h"
#include "buffer.h"
+#include "bufaux.h"
#include "cipher.h"
#include "kex.h"
#include "key.h"
@@ -82,6 +82,7 @@ RCSID("$OpenBSD: sshd.c,v 1.286 2004/02/23 12:02:33 markus Exp $");
#include "canohost.h"
#include "auth.h"
#include "misc.h"
+#include "msg.h"
#include "dispatch.h"
#include "channels.h"
#include "session.h"
@@ -101,11 +102,13 @@ int deny_severity = LOG_WARNING;
#define O_NOCTTY 0
#endif
-#ifdef HAVE___PROGNAME
+/* Re-exec fds */
+#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
+#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
+#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3)
+#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4)
+
extern char *__progname;
-#else
-char *__progname;
-#endif
/* Server configuration options. */
ServerOptions options;
@@ -143,6 +146,12 @@ int log_stderr = 0;
char **saved_argv;
int saved_argc;
+/* re-exec */
+int rexeced_flag = 0;
+int rexec_flag = 1;
+int rexec_argc = 0;
+char **rexec_argv;
+
/*
* The sockets that the server is listening; this is used in the SIGHUP
* signal handler.
@@ -206,12 +215,12 @@ int startup_pipe; /* in child */
int use_privsep;
struct monitor *pmonitor = NULL;
-/* message to be displayed after login */
-Buffer loginmsg;
-
/* global authentication context */
Authctxt *the_authctxt = NULL;
+/* message to be displayed after login */
+Buffer loginmsg;
+
/* Prototypes for various functions defined later in this file. */
void destroy_sensitive_data(void);
void demote_sensitive_data(void);
@@ -655,6 +664,7 @@ privsep_postauth(Authctxt *authctxt)
else if (pmonitor->m_pid != 0) {
debug2("User child is on pid %ld", (long)pmonitor->m_pid);
close(pmonitor->m_recvfd);
+ buffer_clear(&loginmsg);
monitor_child_postauth(pmonitor);
/* NEVERREACHED */
@@ -777,6 +787,87 @@ usage(void)
exit(1);
}
+static void
+send_rexec_state(int fd, Buffer *conf)
+{
+ Buffer m;
+
+ debug3("%s: entering fd = %d config len %d", __func__, fd,
+ buffer_len(conf));
+
+ /*
+ * Protocol from reexec master to child:
+ * string configuration
+ * u_int ephemeral_key_follows
+ * bignum e (only if ephemeral_key_follows == 1)
+ * bignum n "
+ * bignum d "
+ * bignum iqmp "
+ * bignum p "
+ * bignum q "
+ */
+ buffer_init(&m);
+ buffer_put_cstring(&m, buffer_ptr(conf));
+
+ if (sensitive_data.server_key != NULL &&
+ sensitive_data.server_key->type == KEY_RSA1) {
+ buffer_put_int(&m, 1);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->e);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->n);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->d);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->p);
+ buffer_put_bignum(&m, sensitive_data.server_key->rsa->q);
+ } else
+ buffer_put_int(&m, 0);
+
+ if (ssh_msg_send(fd, 0, &m) == -1)
+ fatal("%s: ssh_msg_send failed", __func__);
+
+ buffer_free(&m);
+
+ debug3("%s: done", __func__);
+}
+
+static void
+recv_rexec_state(int fd, Buffer *conf)
+{
+ Buffer m;
+ char *cp;
+ u_int len;
+
+ debug3("%s: entering fd = %d", __func__, fd);
+
+ buffer_init(&m);
+
+ if (ssh_msg_recv(fd, &m) == -1)
+ fatal("%s: ssh_msg_recv failed", __func__);
+ if (buffer_get_char(&m) != 0)
+ fatal("%s: rexec version mismatch", __func__);
+
+ cp = buffer_get_string(&m, &len);
+ if (conf != NULL)
+ buffer_append(conf, cp, len + 1);
+ xfree(cp);
+
+ if (buffer_get_int(&m)) {
+ if (sensitive_data.server_key != NULL)
+ key_free(sensitive_data.server_key);
+ sensitive_data.server_key = key_new_private(KEY_RSA1);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->e);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->n);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->d);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->p);
+ buffer_get_bignum(&m, sensitive_data.server_key->rsa->q);
+ rsa_generate_additional_parameters(
+ sensitive_data.server_key->rsa);
+ }
+ buffer_free(&m);
+
+ debug3("%s: done", __func__);
+}
+
/*
* Main program for the daemon.
*/
@@ -785,7 +876,8 @@ main(int ac, char **av)
{
extern char *optarg;
extern int optind;
- int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
+ int opt, j, i, fdsetsz, on = 1;
+ int sock_in = -1, sock_out = -1, newsock = -1;
pid_t pid;
socklen_t fromlen;
fd_set *fdset;
@@ -797,11 +889,12 @@ main(int ac, char **av)
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
char *line;
int listen_sock, maxfd;
- int startup_p[2];
+ int startup_p[2], config_s[2];
int startups = 0;
Key *key;
Authctxt *authctxt;
int ret, key_used = 0;
+ Buffer cfg;
#ifdef HAVE_SECUREWARE
(void)set_auth_parameters(ac, av);
@@ -811,6 +904,7 @@ main(int ac, char **av)
/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
saved_argc = ac;
+ rexec_argc = ac;
saved_argv = xmalloc(sizeof(*saved_argv) * (ac + 1));
for (i = 0; i < ac; i++)
saved_argv[i] = xstrdup(av[i]);
@@ -829,7 +923,7 @@ main(int ac, char **av)
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqtQ46")) != -1) {
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) {
switch (opt) {
case '4':
IPv4or6 = AF_INET;
@@ -856,6 +950,13 @@ main(int ac, char **av)
case 'i':
inetd_flag = 1;
break;
+ case 'r':
+ rexec_flag = 0;
+ break;
+ case 'R':
+ rexeced_flag = 1;
+ inetd_flag = 1;
+ break;
case 'Q':
/* ignored */
break;
@@ -919,6 +1020,15 @@ main(int ac, char **av)
break;
}
}
+ if (rexeced_flag || inetd_flag)
+ rexec_flag = 0;
+ if (rexec_flag && (av[0] == NULL || *av[0] != '/'))
+ fatal("sshd re-exec requires execution with an absolute path");
+ if (rexeced_flag)
+ closefrom(REEXEC_MIN_FREE_FD);
+ else
+ closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
+
SSLeay_add_all_algorithms();
channel_set_af(IPv4or6);
@@ -941,7 +1051,7 @@ main(int ac, char **av)
unsetenv("KRB5CCNAME");
#endif /* _AIX */
#ifdef _UNICOS
- /* Cray can define user privs drop all prives now!
+ /* Cray can define user privs drop all privs now!
* Not needed on PRIV_SU systems!
*/
drop_cray_privs();
@@ -949,8 +1059,23 @@ main(int ac, char **av)
seed_rng();
- /* Read server configuration options from the configuration file. */
- read_server_config(&options, config_file_name);
+ sensitive_data.server_key = NULL;
+ sensitive_data.ssh1_host_key = NULL;
+ sensitive_data.have_ssh1_key = 0;
+ sensitive_data.have_ssh2_key = 0;
+
+ /* Fetch our configuration */
+ buffer_init(&cfg);
+ if (rexeced_flag)
+ recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg);
+ else
+ load_server_config(config_file_name, &cfg);
+
+ parse_server_config(&options,
+ rexeced_flag ? "rexec" : config_file_name, &cfg);
+
+ if (!rexec_flag)
+ buffer_free(&cfg);
/* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options);
@@ -968,10 +1093,6 @@ main(int ac, char **av)
sizeof(Key *));
for (i = 0; i < options.num_host_key_files; i++)
sensitive_data.host_keys[i] = NULL;
- sensitive_data.server_key = NULL;
- sensitive_data.ssh1_host_key = NULL;
- sensitive_data.have_ssh1_key = 0;
- sensitive_data.have_ssh2_key = 0;
for (i = 0; i < options.num_host_key_files; i++) {
key = key_load_private(options.host_key_files[i], "", NULL);
@@ -1070,6 +1191,16 @@ main(int ac, char **av)
if (setgroups(0, NULL) < 0)
debug("setgroups() failed: %.200s", strerror(errno));
+ if (rexec_flag) {
+ rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2));
+ for (i = 0; i < rexec_argc; i++) {
+ debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
+ rexec_argv[i] = saved_argv[i];
+ }
+ rexec_argv[rexec_argc] = "-R";
+ rexec_argv[rexec_argc + 1] = NULL;
+ }
+
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && !inetd_flag)
log_stderr = 1;
@@ -1111,19 +1242,34 @@ main(int ac, char **av)
/* Start listening for a socket, unless started from inetd. */
if (inetd_flag) {
- int s1;
- s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
- dup(s1);
- sock_in = dup(0);
- sock_out = dup(1);
+ int fd;
+
startup_pipe = -1;
+ if (rexeced_flag) {
+ close(REEXEC_CONFIG_PASS_FD);
+ sock_in = sock_out = dup(STDIN_FILENO);
+ if (!debug_flag) {
+ startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);
+ close(REEXEC_STARTUP_PIPE_FD);
+ }
+ } else {
+ sock_in = dup(STDIN_FILENO);
+ sock_out = dup(STDOUT_FILENO);
+ }
/*
* We intentionally do not close the descriptors 0, 1, and 2
- * as our code for setting the descriptors won\'t work if
+ * as our code for setting the descriptors won't work if
* ttyfd happens to be one of those.
*/
+ if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ if (fd > STDOUT_FILENO)
+ close(fd);
+ }
debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
- if (options.protocol & SSH_PROTO_1)
+ if ((options.protocol & SSH_PROTO_1) &&
+ sensitive_data.server_key == NULL)
generate_ephemeral_server_key();
} else {
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
@@ -1146,8 +1292,7 @@ main(int ac, char **av)
verbose("socket: %.100s", strerror(errno));
continue;
}
- if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {
- error("listen_sock O_NONBLOCK: %s", strerror(errno));
+ if (set_nonblock(listen_sock) == -1) {
close(listen_sock);
continue;
}
@@ -1290,8 +1435,7 @@ main(int ac, char **av)
error("accept: %.100s", strerror(errno));
continue;
}
- if (fcntl(newsock, F_SETFL, 0) < 0) {
- error("newsock del O_NONBLOCK: %s", strerror(errno));
+ if (unset_nonblock(newsock) == -1) {
close(newsock);
continue;
}
@@ -1305,6 +1449,16 @@ main(int ac, char **av)
continue;
}
+ if (rexec_flag && socketpair(AF_UNIX,
+ SOCK_STREAM, 0, config_s) == -1) {
+ error("reexec socketpair: %s",
+ strerror(errno));
+ close(newsock);
+ close(startup_p[0]);
+ close(startup_p[1]);
+ continue;
+ }
+
for (j = 0; j < options.max_startups; j++)
if (startup_pipes[j] == -1) {
startup_pipes[j] = startup_p[0];
@@ -1328,8 +1482,15 @@ main(int ac, char **av)
close_listen_socks();
sock_in = newsock;
sock_out = newsock;
+ close(startup_p[0]);
+ close(startup_p[1]);
startup_pipe = -1;
pid = getpid();
+ if (rexec_flag) {
+ send_rexec_state(config_s[0],
+ &cfg);
+ close(config_s[0]);
+ }
break;
} else {
/*
@@ -1351,6 +1512,7 @@ main(int ac, char **av)
sock_in = newsock;
sock_out = newsock;
log_init(__progname, options.log_level, options.log_facility, log_stderr);
+ close(config_s[0]);
break;
}
}
@@ -1363,6 +1525,12 @@ main(int ac, char **av)
close(startup_p[1]);
+ if (rexec_flag) {
+ send_rexec_state(config_s[0], &cfg);
+ close(config_s[0]);
+ close(config_s[1]);
+ }
+
/* Mark that the key has been used (it was "given" to the child). */
if ((options.protocol & SSH_PROTO_1) &&
key_used == 0) {
@@ -1401,6 +1569,46 @@ main(int ac, char **av)
error("setsid: %.100s", strerror(errno));
#endif
+ if (rexec_flag) {
+ int fd;
+
+ debug("rexec start in %d out %d newsock %d pipe %d sock %d",
+ sock_in, sock_out, newsock, startup_pipe, config_s[0]);
+ dup2(newsock, STDIN_FILENO);
+ dup2(STDIN_FILENO, STDOUT_FILENO);
+ if (startup_pipe == -1)
+ close(REEXEC_STARTUP_PIPE_FD);
+ else
+ dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD);
+
+ dup2(config_s[1], REEXEC_CONFIG_PASS_FD);
+ close(config_s[1]);
+ if (startup_pipe != -1)
+ close(startup_pipe);
+
+ execv(rexec_argv[0], rexec_argv);
+
+ /* Reexec has failed, fall back and continue */
+ error("rexec of %s failed: %s", rexec_argv[0], strerror(errno));
+ recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL);
+ log_init(__progname, options.log_level,
+ options.log_facility, log_stderr);
+
+ /* Clean up fds */
+ startup_pipe = REEXEC_STARTUP_PIPE_FD;
+ close(config_s[1]);
+ close(REEXEC_CONFIG_PASS_FD);
+ newsock = sock_out = sock_in = dup(STDIN_FILENO);
+ if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+ debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d",
+ sock_in, sock_out, newsock, startup_pipe, config_s[0]);
+ }
+
/*
* Disable the key regeneration alarm. We will not regenerate the
* key since we are no longer in a position to give it to anyone. We
@@ -1442,7 +1650,7 @@ main(int ac, char **av)
#ifdef LIBWRAP
/* Check whether logins are denied from this host. */
- {
+ if (packet_connection_is_on_socket()) {
struct request_info req;
request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
@@ -1490,6 +1698,9 @@ main(int ac, char **av)
if (privsep_preauth(authctxt) == 1)
goto authenticated;
+ /* prepare buffer to collect messages to display to user after login */
+ buffer_init(&loginmsg);
+
/* perform the key exchange */
/* authenticate user and start session */
if (compat20) {
@@ -1705,9 +1916,10 @@ do_ssh1_kex(void)
BN_bn2bin(session_key_int,
session_key + sizeof(session_key) - len);
- compute_session_id(session_id, cookie,
+ derive_ssh1_session_id(
sensitive_data.ssh1_host_key->rsa->n,
- sensitive_data.server_key->rsa->n);
+ sensitive_data.server_key->rsa->n,
+ cookie, session_id);
/*
* Xor the first 16 bytes of the session key with the
* session id.
@@ -1790,6 +2002,7 @@ do_ssh2_kex(void)
/* start key exchange */
kex = kex_setup(myproposal);
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
+ kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->server = 1;
kex->client_version_string=client_version_string;