]> andersk Git - gssapi-openssh.git/blobdiff - openssh/sshd.c
Merge from OPENSSH_3_8_1P1_GSSAPI_20040713 to OPENSSH_3_9P1_GSSAPI_20040818.
[gssapi-openssh.git] / openssh / sshd.c
index 9c65119376f98807359262480b46442f24877786..1ad01f0b291670a1197a216f97310e317f7bcd8c 100644 (file)
@@ -42,7 +42,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.290 2004/03/11 10:21:17 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.301 2004/08/11 11:50:09 dtucker Exp $");
 
 #include <openssl/dh.h>
 #include <openssl/bn.h>
@@ -60,12 +60,12 @@ RCSID("$OpenBSD: sshd.c,v 1.290 2004/03/11 10:21:17 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"
@@ -77,6 +77,7 @@ RCSID("$OpenBSD: sshd.c,v 1.290 2004/03/11 10:21:17 markus Exp $");
 #include "canohost.h"
 #include "auth.h"
 #include "misc.h"
+#include "msg.h"
 #include "dispatch.h"
 #include "channels.h"
 #include "session.h"
@@ -105,11 +106,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;
@@ -147,6 +150,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.
@@ -210,12 +219,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);
@@ -659,6 +668,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 */
@@ -781,6 +791,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.
  */
@@ -789,7 +880,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;
@@ -801,11 +893,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);
@@ -817,6 +910,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]);
@@ -835,7 +929,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;
@@ -862,6 +956,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;
@@ -925,6 +1026,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);
 
@@ -947,7 +1057,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();
@@ -955,8 +1065,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);
@@ -974,10 +1099,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);
@@ -1079,6 +1200,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;
@@ -1120,19 +1251,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) {
@@ -1155,8 +1301,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;
                        }
@@ -1299,8 +1444,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;
                                }
@@ -1314,6 +1458,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];
@@ -1337,8 +1491,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 {
                                        /*
@@ -1360,6 +1521,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;
                                        }
                                }
@@ -1372,6 +1534,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) {
@@ -1410,6 +1578,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
@@ -1440,7 +1648,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);
@@ -1495,6 +1703,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) {
@@ -1710,9 +1921,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.
@@ -1834,6 +2046,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;
 #ifdef GSSAPI
        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
This page took 0.066751 seconds and 4 git commands to generate.