]> andersk Git - openssh.git/blobdiff - sshd.c
- deraadt@cvs.openbsd.org 2001/02/04 16:56:23
[openssh.git] / sshd.c
diff --git a/sshd.c b/sshd.c
index aa7e016bfe8fd4cd2c1f8629d958659e2325792f..e329112992a418caf50f3e90beb6ec2fa97ab49c 100644 (file)
--- a/sshd.c
+++ b/sshd.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.146 2001/01/07 11:28:07 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.163 2001/02/04 23:56:23 deraadt Exp $");
 
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/hmac.h>
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
 #include "xmalloc.h"
 #include "rsa.h"
-#include "ssh.h"
 #include "pty.h"
 #include "packet.h"
 #include "mpaux.h"
+#include "log.h"
 #include "servconf.h"
 #include "uidswap.h"
 #include "compat.h"
 #include "buffer.h"
-
-#include "ssh2.h"
-#include <openssl/dh.h>
-#include <openssl/bn.h>
-#include <openssl/hmac.h>
+#include "cipher.h"
 #include "kex.h"
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
 #include "key.h"
 #include "dh.h"
-
-#include "auth.h"
 #include "myproposal.h"
 #include "authfile.h"
+#include "pathnames.h"
+#include "atomicio.h"
+#include "canohost.h"
+#include "auth.h"
+#include "misc.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -88,7 +92,7 @@ char *__progname;
 ServerOptions options;
 
 /* Name of the server configuration file. */
-char *config_file_name = SERVER_CONFIG_FILE;
+char *config_file_name = _PATH_SERVER_CONFIG_FILE;
 
 /*
  * Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
@@ -153,10 +157,10 @@ struct {
 } sensitive_data;
 
 /*
- * Flag indicating whether the current session key has been used.  This flag
- * is set whenever the key is used, and cleared when the key is regenerated.
+ * Flag indicating whether the RSA server key needs to be regenerated.
+ * Is set in the SIGALRM handler and cleared when the key is regenerated.
  */
-int key_used = 0;
+int key_do_regen = 0;
 
 /* This is set to true when SIGHUP is received. */
 int received_sighup = 0;
@@ -267,7 +271,6 @@ grace_alarm_handler(int sig)
  * Thus there should be no concurrency control/asynchronous execution
  * problems.
  */
-/* XXX do we really want this work to be done in a signal handler ? -m */
 void
 generate_empheral_server_key(void)
 {
@@ -279,21 +282,14 @@ generate_empheral_server_key(void)
        arc4random_stir();
        log("RSA key generation complete.");
 }
+
 void
 key_regeneration_alarm(int sig)
 {
        int save_errno = errno;
-
-       /* Check if we should generate a new key. */
-       if (key_used) {
-               /* This should really be done in the background. */
-               generate_empheral_server_key();
-               key_used = 0;
-       }
-       /* Reschedule the alarm. */
-       signal(SIGALRM, key_regeneration_alarm);
-       alarm(options.key_regeneration_time);
+       signal(SIGALRM, SIG_DFL);
        errno = save_errno;
+       key_do_regen = 1;
 }
 
 void
@@ -433,7 +429,7 @@ destroy_sensitive_data(void)
                key_free(sensitive_data.server_key);
                sensitive_data.server_key = NULL;
        }
-        for(i = 0; i < options.num_host_key_files; i++) {
+       for(i = 0; i < options.num_host_key_files; i++) {
                if (sensitive_data.host_keys[i]) {
                        key_free(sensitive_data.host_keys[i]);
                        sensitive_data.host_keys[i] = NULL;
@@ -555,7 +551,6 @@ main(int ac, char **av)
        int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
        pid_t pid;
        socklen_t fromlen;
-       int silent = 0;
        fd_set *fdset;
        struct sockaddr_storage from;
        const char *remote_ip;
@@ -567,6 +562,7 @@ main(int ac, char **av)
        int listen_sock, maxfd;
        int startup_p[2];
        int startups = 0;
+       int ret, key_used = 0;
 
        __progname = get_progname(av[0]);
        init_rng();
@@ -579,7 +575,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:V:u:dDiqQ46")) != EOF) {
+       while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDiqQ46")) != -1) {
                switch (opt) {
                case '4':
                        IPv4or6 = AF_INET;
@@ -608,7 +604,7 @@ main(int ac, char **av)
                        inetd_flag = 1;
                        break;
                case 'Q':
-                       silent = 1;
+                       /* ignored */
                        break;
                case 'q':
                        options.log_level = SYSLOG_LEVEL_QUIET;
@@ -650,7 +646,7 @@ main(int ac, char **av)
                        fprintf(stderr, "sshd version %s\n", SSH_VERSION);
                        fprintf(stderr, "Usage: %s [options]\n", __progname);
                        fprintf(stderr, "Options:\n");
-                       fprintf(stderr, "  -f file    Configuration file (default %s)\n", SERVER_CONFIG_FILE);
+                       fprintf(stderr, "  -f file    Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
                        fprintf(stderr, "  -d         Debugging mode (multiple -d means more debugging)\n");
                        fprintf(stderr, "  -i         Started from inetd\n");
                        fprintf(stderr, "  -D         Do not fork into daemon mode\n");
@@ -660,7 +656,7 @@ main(int ac, char **av)
                        fprintf(stderr, "  -g seconds Grace period for authentication (default: 600)\n");
                        fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");
                        fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",
-                           HOST_KEY_FILE);
+                           _PATH_HOST_KEY_FILE);
                        fprintf(stderr, "  -u len     Maximum hostname length for utmp recording\n");
                        fprintf(stderr, "  -4         Use IPv4 only\n");
                        fprintf(stderr, "  -6         Use IPv6 only\n");
@@ -673,9 +669,9 @@ main(int ac, char **av)
         * key (unless started from inetd)
         */
        log_init(__progname,
-           options.log_level == -1 ? SYSLOG_LEVEL_NOTICE : options.log_level,
+           options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
            options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
-           !silent && !inetd_flag);
+           !inetd_flag);
 
        /* Read server configuration options from the configuration file. */
        read_server_config(&options, config_file_name);
@@ -727,9 +723,7 @@ main(int ac, char **av)
                log("Disabling protocol version 2. Could not load host key");
                options.protocol &= ~SSH_PROTO_2;
        }
-       if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
-               if (silent == 0)
-                       fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
+       if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
                log("sshd: no hostkeys available -- exiting.\n");
                exit(1);
        }
@@ -889,14 +883,9 @@ main(int ac, char **av)
                                fclose(f);
                        }
                }
-               if (options.protocol & SSH_PROTO_1) {
+               if (options.protocol & SSH_PROTO_1)
                        generate_empheral_server_key();
 
-                       /* Schedule server key regeneration alarm. */
-                       signal(SIGALRM, key_regeneration_alarm);
-                       alarm(options.key_regeneration_time);
-               }
-
                /* Arrange to restart on SIGHUP.  The handler needs listen_sock. */
                signal(SIGHUP, sighup_handler);
 
@@ -926,7 +915,7 @@ main(int ac, char **av)
                                sighup_restart();
                        if (fdset != NULL)
                                xfree(fdset);
-                       fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+                       fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
                        fdset = (fd_set *)xmalloc(fdsetsz);
                        memset(fdset, 0, fdsetsz);
 
@@ -937,11 +926,17 @@ main(int ac, char **av)
                                        FD_SET(startup_pipes[i], fdset);
 
                        /* Wait in select until there is a connection. */
-                       if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
-                               if (errno != EINTR)
-                                       error("select: %.100s", strerror(errno));
-                               continue;
+                       ret = select(maxfd+1, fdset, NULL, NULL, NULL);
+                       if (ret < 0 && errno != EINTR)
+                               error("select: %.100s", strerror(errno));
+                       if (key_used && key_do_regen) {
+                               generate_empheral_server_key();
+                               key_used = 0;
+                               key_do_regen = 0;
                        }
+                       if (ret < 0)
+                               continue;
+
                        for (i = 0; i < options.max_startups; i++)
                                if (startup_pipes[i] != -1 &&
                                    FD_ISSET(startup_pipes[i], fdset)) {
@@ -988,7 +983,7 @@ main(int ac, char **av)
                                                startups++;
                                                break;
                                        }
-                               
+
                                /*
                                 * Got connection.  Fork a child to handle it, unless
                                 * we are in debugging mode.
@@ -1041,7 +1036,13 @@ main(int ac, char **av)
                                close(startup_p[1]);
 
                                /* Mark that the key has been used (it was "given" to the child). */
-                               key_used = 1;
+                               if ((options.protocol & SSH_PROTO_1) &&
+                                   key_used == 0) {
+                                       /* Schedule server key regeneration alarm. */
+                                       signal(SIGALRM, key_regeneration_alarm);
+                                       alarm(options.key_regeneration_time);
+                                       key_used = 1;
+                               }
 
                                arc4random_stir();
 
@@ -1079,6 +1080,12 @@ main(int ac, char **av)
        linger.l_linger = 5;
        setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
 
+       /* Set keepalives if requested. */
+       if (options.keepalives &&
+           setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
+           sizeof(on)) < 0)
+               error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
+
        /*
         * Register our connection.  This turns encryption off because we do
         * not have a key.
@@ -1179,6 +1186,7 @@ do_ssh1_kex(void)
 {
        int i, len;
        int plen, slen;
+       int rsafail = 0;
        BIGNUM *session_key_int;
        u_char session_key[SSH_SESSION_KEY_LENGTH];
        u_char cookie[8];
@@ -1244,10 +1252,8 @@ do_ssh1_kex(void)
        if (options.afs_token_passing)
                auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
 #endif
-#ifdef SKEY
-       if (options.skey_authentication == 1)
+       if (options.challenge_reponse_authentication == 1)
                auth_mask |= 1 << SSH_AUTH_TIS;
-#endif
        if (options.password_authentication)
                auth_mask |= 1 << SSH_AUTH_PASSWORD;
        packet_put_int(auth_mask);
@@ -1291,7 +1297,7 @@ do_ssh1_kex(void)
         * with larger modulus first).
         */
        if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) {
-               /* Private key has bigger modulus. */
+               /* Server key has bigger modulus. */
                if (BN_num_bits(sensitive_data.server_key->rsa->n) <
                    BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
                        fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
@@ -1300,10 +1306,12 @@ do_ssh1_kex(void)
                            BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
                            SSH_KEY_BITS_RESERVED);
                }
-               rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.server_key->rsa);
-               rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.ssh1_host_key->rsa);
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.server_key->rsa) <= 0)
+                       rsafail++;
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.ssh1_host_key->rsa) <= 0)
+                       rsafail++;
        } else {
                /* Host key has bigger modulus (or they are equal). */
                if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <
@@ -1314,10 +1322,12 @@ do_ssh1_kex(void)
                            BN_num_bits(sensitive_data.server_key->rsa->n),
                            SSH_KEY_BITS_RESERVED);
                }
-               rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.ssh1_host_key->rsa);
-               rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.server_key->rsa);
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.ssh1_host_key->rsa) < 0)
+                       rsafail++;
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.server_key->rsa) < 0)
+                       rsafail++;
        }
 
        compute_session_id(session_id, cookie,
@@ -1332,15 +1342,29 @@ do_ssh1_kex(void)
         * least significant 256 bits of the integer; the first byte of the
         * key is in the highest bits.
         */
-       BN_mask_bits(session_key_int, sizeof(session_key) * 8);
-       len = BN_num_bytes(session_key_int);
-       if (len < 0 || len > sizeof(session_key))
-               fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d",
-                   get_remote_ipaddr(),
-                   len, sizeof(session_key));
-       memset(session_key, 0, sizeof(session_key));
-       BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
-
+       if (!rsafail) {
+               BN_mask_bits(session_key_int, sizeof(session_key) * 8);
+               len = BN_num_bytes(session_key_int);
+               if (len < 0 || len > sizeof(session_key)) {
+                       error("do_connection: bad session key len from %s: "
+                           "session_key_int %d > sizeof(session_key) %d",
+                           get_remote_ipaddr(), len, (int)sizeof(session_key));
+                       rsafail++;
+               } else {
+                       memset(session_key, 0, sizeof(session_key));
+                       BN_bn2bin(session_key_int,
+                           session_key + sizeof(session_key) - len);
+               }
+       }
+       if (rsafail) {
+               log("do_connection: generating a fake encryption key");
+               for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+                       if (i % 4 == 0)
+                               rand = arc4random();
+                       session_key[i] = rand & 0xff;
+                       rand >>= 8;
+               }
+       }
        /* Destroy the decrypted integer.  It is no longer needed. */
        BN_clear_free(session_key_int);
 
@@ -1483,7 +1507,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        fprintf(stderr, "\npub= ");
        BN_print_fp(stderr, dh->pub_key);
        fprintf(stderr, "\n");
-        DHparams_print_fp(stderr, dh);
+       DHparams_print_fp(stderr, dh);
 #endif
        if (!dh_pub_is_valid(dh, dh_client_pub))
                packet_disconnect("bad client public DH value");
@@ -1523,6 +1547,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        buffer_free(server_kexinit);
        xfree(client_kexinit);
        xfree(server_kexinit);
+       BN_free(dh_client_pub);
 #ifdef DEBUG_KEXDH
        fprintf(stderr, "hash == ");
        for (i = 0; i< 20; i++)
@@ -1552,6 +1577,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        packet_write_wait();
 
        kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
        packet_set_kex(kex);
 
        /* have keys, free DH */
@@ -1624,7 +1650,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        fprintf(stderr, "\npub= ");
        BN_print_fp(stderr, dh->pub_key);
        fprintf(stderr, "\n");
-        DHparams_print_fp(stderr, dh);
+       DHparams_print_fp(stderr, dh);
 #endif
        if (!dh_pub_is_valid(dh, dh_client_pub))
                packet_disconnect("bad client public DH value");
@@ -1665,6 +1691,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        buffer_free(server_kexinit);
        xfree(client_kexinit);
        xfree(server_kexinit);
+       BN_free(dh_client_pub);
 #ifdef DEBUG_KEXDH
        fprintf(stderr, "hash == ");
        for (i = 0; i< 20; i++)
@@ -1694,6 +1721,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
        packet_write_wait();
 
        kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
        packet_set_kex(kex);
 
        /* have keys, free DH */
This page took 0.081157 seconds and 4 git commands to generate.