Merge branch 'vendor/OPENSSH'
[dragonfly.git] / crypto / openssh / sshd.c
index d3c94be..d64bc21 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.393 2012/07/10 02:19:15 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.428 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include <string.h>
 #include <unistd.h>
 
+#ifdef WITH_OPENSSL
 #include <openssl/dh.h>
 #include <openssl/bn.h>
-#include <openssl/md5.h>
 #include <openssl/rand.h>
 #include "openbsd-compat/openssl-compat.h"
+#endif
 
 #ifdef HAVE_SECUREWARE
 #include <sys/security.h>
 #include "packet.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "uidswap.h"
 #include "compat.h"
 #include "cipher.h"
+#include "digest.h"
 #include "key.h"
 #include "kex.h"
-#include "dh.h"
 #include "myproposal.h"
 #include "authfile.h"
 #include "pathnames.h"
 #include "canohost.h"
 #include "hostfile.h"
 #include "auth.h"
-#include "misc.h"
+#include "authfd.h"
 #include "msg.h"
 #include "dispatch.h"
 #include "channels.h"
 #include "ssh-sandbox.h"
 #include "version.h"
 
-#ifdef LIBWRAP
-#include <tcpd.h>
-#include <syslog.h>
-int allow_severity;
-int deny_severity;
-#endif /* LIBWRAP */
-
 #ifndef O_NOCTTY
 #define O_NOCTTY       0
 #endif
@@ -198,6 +193,10 @@ char *server_version_string = NULL;
 /* for rekeying XXX fixme */
 Kex *xxx_kex;
 
+/* Daemon's agent connection */
+AuthenticationConnection *auth_conn = NULL;
+int have_agent = 0;
+
 /*
  * Any really sensitive data in the application is contained in this
  * structure. The idea is that this structure could be locked into memory so
@@ -210,6 +209,7 @@ struct {
        Key     *server_key;            /* ephemeral server key */
        Key     *ssh1_host_key;         /* ssh1 host key */
        Key     **host_keys;            /* all private host keys */
+       Key     **host_pubkeys;         /* all public host keys */
        Key     **host_certificates;    /* all public host certificates */
        int     have_ssh1_key;
        int     have_ssh2_key;
@@ -261,7 +261,9 @@ struct passwd *privsep_pw = NULL;
 void destroy_sensitive_data(void);
 void demote_sensitive_data(void);
 
+#ifdef WITH_SSH1
 static void do_ssh1_kex(void);
+#endif
 static void do_ssh2_kex(void);
 
 /*
@@ -313,6 +315,7 @@ static void
 sighup_restart(void)
 {
        logit("Received SIGHUP; restarting.");
+       platform_pre_restart();
        close_listen_socks();
        close_startup_pipes();
        alarm(0);  /* alarm timer persists across exec */
@@ -363,6 +366,15 @@ grace_alarm_handler(int sig)
        if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
                kill(pmonitor->m_pid, SIGALRM);
 
+       /*
+        * Try to kill any processes that we have spawned, E.g. authorized
+        * keys command helpers.
+        */
+       if (getpgid(0) == getpid()) {
+               signal(SIGTERM, SIG_IGN);
+               kill(0, SIGTERM);
+       }
+
        /* Log error and exit. */
        sigdie("Timeout before authentication for %s", get_remote_ipaddr());
 }
@@ -386,7 +398,6 @@ generate_ephemeral_server_key(void)
        verbose("RSA key generation complete.");
 
        arc4random_buf(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
-       arc4random_stir();
 }
 
 /*ARGSUSED*/
@@ -469,10 +480,11 @@ sshd_exchange_identification(int sock_in, int sock_out)
            &remote_major, &remote_minor, remote_version) != 3) {
                s = "Protocol mismatch.\n";
                (void) atomicio(vwrite, sock_out, s, strlen(s));
+               logit("Bad protocol version identification '%.100s' "
+                   "from %s port %d", client_version_string,
+                   get_remote_ipaddr(), get_remote_port());
                close(sock_in);
                close(sock_out);
-               logit("Bad protocol version identification '%.100s' from %s",
-                   client_version_string, get_remote_ipaddr());
                cleanup_exit(255);
        }
        debug("Client protocol version %d.%d; client software version %.100s",
@@ -483,17 +495,24 @@ sshd_exchange_identification(int sock_in, int sock_out)
 
        compat_datafellows(remote_version);
 
-       if (datafellows & SSH_BUG_PROBE) {
+       if ((datafellows & SSH_BUG_PROBE) != 0) {
                logit("probed from %s with %s.  Don't panic.",
                    get_remote_ipaddr(), client_version_string);
                cleanup_exit(255);
        }
-
-       if (datafellows & SSH_BUG_SCANNER) {
+       if ((datafellows & SSH_BUG_SCANNER) != 0) {
                logit("scanned from %s with %s.  Don't panic.",
                    get_remote_ipaddr(), client_version_string);
                cleanup_exit(255);
        }
+       if ((datafellows & SSH_BUG_RSASIGMD5) != 0) {
+               logit("Client version \"%.100s\" uses unsafe RSA signature "
+                   "scheme; disabling use of RSA keys", remote_version);
+       }
+       if ((datafellows & SSH_BUG_DERIVEKEY) != 0) {
+               fatal("Client version \"%.100s\" uses unsafe key agreement; "
+                   "refusing connection", remote_version);
+       }
 
        mismatch = 0;
        switch (remote_major) {
@@ -563,7 +582,7 @@ destroy_sensitive_data(void)
                }
        }
        sensitive_data.ssh1_host_key = NULL;
-       memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
+       explicit_bzero(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
 }
 
 /* Demote private to public keys for network child */
@@ -602,9 +621,16 @@ privsep_preauth_child(void)
        /* Enable challenge-response authentication for privilege separation */
        privsep_challenge_enable();
 
+#ifdef GSSAPI
+       /* Cache supported mechanism OIDs for later use */
+       if (options.gss_authentication)
+               ssh_gssapi_prepare_supported_oids();
+#endif
+
        arc4random_stir();
        arc4random_buf(rnd, sizeof(rnd));
        RAND_seed(rnd, sizeof(rnd));
+       explicit_bzero(rnd, sizeof(rnd));
 
        /* Demote the private keys to public keys. */
        demote_sensitive_data();
@@ -643,7 +669,7 @@ privsep_preauth(Authctxt *authctxt)
        pmonitor->m_pkex = &xxx_kex;
 
        if (use_privsep == PRIVSEP_ON)
-               box = ssh_sandbox_init();
+               box = ssh_sandbox_init(pmonitor);
        pid = fork();
        if (pid == -1) {
                fatal("fork of unprivileged child failed");
@@ -651,6 +677,8 @@ privsep_preauth(Authctxt *authctxt)
                debug2("Network child is on pid %ld", (long)pid);
 
                pmonitor->m_pid = pid;
+               if (have_agent)
+                       auth_conn = ssh_get_authentication_connection();
                if (box != NULL)
                        ssh_sandbox_parent_preauth(box, pid);
                monitor_child_preauth(authctxt, pmonitor);
@@ -737,6 +765,7 @@ privsep_postauth(Authctxt *authctxt)
        arc4random_stir();
        arc4random_buf(rnd, sizeof(rnd));
        RAND_seed(rnd, sizeof(rnd));
+       explicit_bzero(rnd, sizeof(rnd));
 
        /* Drop privileges */
        do_setusercontext(authctxt->pw);
@@ -764,12 +793,15 @@ list_hostkey_types(void)
        buffer_init(&b);
        for (i = 0; i < options.num_host_key_files; i++) {
                key = sensitive_data.host_keys[i];
+               if (key == NULL)
+                       key = sensitive_data.host_pubkeys[i];
                if (key == NULL)
                        continue;
                switch (key->type) {
                case KEY_RSA:
                case KEY_DSA:
                case KEY_ECDSA:
+               case KEY_ED25519:
                        if (buffer_len(&b) > 0)
                                buffer_append(&b, ",", 1);
                        p = key_ssh_name(key);
@@ -786,6 +818,7 @@ list_hostkey_types(void)
                case KEY_RSA_CERT:
                case KEY_DSA_CERT:
                case KEY_ECDSA_CERT:
+               case KEY_ED25519_CERT:
                        if (buffer_len(&b) > 0)
                                buffer_append(&b, ",", 1);
                        p = key_ssh_name(key);
@@ -813,10 +846,13 @@ get_hostkey_by_type(int type, int need_private)
                case KEY_RSA_CERT:
                case KEY_DSA_CERT:
                case KEY_ECDSA_CERT:
+               case KEY_ED25519_CERT:
                        key = sensitive_data.host_certificates[i];
                        break;
                default:
                        key = sensitive_data.host_keys[i];
+                       if (key == NULL && !need_private)
+                               key = sensitive_data.host_pubkeys[i];
                        break;
                }
                if (key != NULL && key->type == type)
@@ -846,6 +882,14 @@ get_hostkey_by_index(int ind)
        return (sensitive_data.host_keys[ind]);
 }
 
+Key *
+get_hostkey_public_by_index(int ind)
+{
+       if (ind < 0 || ind >= options.num_host_key_files)
+               return (NULL);
+       return (sensitive_data.host_pubkeys[ind]);
+}
+
 int
 get_hostkey_index(Key *key)
 {
@@ -858,6 +902,8 @@ get_hostkey_index(Key *key)
                } else {
                        if (key == sensitive_data.host_keys[i])
                                return (i);
+                       if (key == sensitive_data.host_pubkeys[i])
+                               return (i);
                }
        }
        return (-1);
@@ -895,11 +941,18 @@ static void
 usage(void)
 {
        fprintf(stderr, "%s, %s\n",
-           SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
+           SSH_RELEASE,
+#ifdef WITH_OPENSSL
+           SSLeay_version(SSLEAY_VERSION)
+#else
+           "without OpenSSL"
+#endif
+       );
        fprintf(stderr,
 "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n"
-"            [-f config_file] [-g login_grace_time] [-h host_key_file]\n"
-"            [-k key_gen_time] [-o option] [-p port] [-u len]\n"
+"            [-E log_file] [-f config_file] [-g login_grace_time]\n"
+"            [-h host_key_file] [-k key_gen_time] [-o option] [-p port]\n"
+"            [-u len]\n"
        );
        exit(1);
 }
@@ -927,6 +980,7 @@ send_rexec_state(int fd, Buffer *conf)
        buffer_init(&m);
        buffer_put_cstring(&m, buffer_ptr(conf));
 
+#ifdef WITH_SSH1
        if (sensitive_data.server_key != NULL &&
            sensitive_data.server_key->type == KEY_RSA1) {
                buffer_put_int(&m, 1);
@@ -937,6 +991,7 @@ send_rexec_state(int fd, Buffer *conf)
                buffer_put_bignum(&m, sensitive_data.server_key->rsa->p);
                buffer_put_bignum(&m, sensitive_data.server_key->rsa->q);
        } else
+#endif
                buffer_put_int(&m, 0);
 
 #ifndef OPENSSL_PRNG_ONLY
@@ -970,9 +1025,10 @@ recv_rexec_state(int fd, Buffer *conf)
        cp = buffer_get_string(&m, &len);
        if (conf != NULL)
                buffer_append(conf, cp, len + 1);
-       xfree(cp);
+       free(cp);
 
        if (buffer_get_int(&m)) {
+#ifdef WITH_SSH1
                if (sensitive_data.server_key != NULL)
                        key_free(sensitive_data.server_key);
                sensitive_data.server_key = key_new_private(KEY_RSA1);
@@ -982,8 +1038,13 @@ recv_rexec_state(int fd, Buffer *conf)
                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);
+               if (rsa_generate_additional_parameters(
+                   sensitive_data.server_key->rsa) != 0)
+                       fatal("%s: rsa_generate_additional_parameters "
+                           "error", __func__);
+#else
+               fatal("ssh1 not supported");
+#endif
        }
 
 #ifndef OPENSSL_PRNG_ONLY
@@ -1021,7 +1082,9 @@ server_accept_inetd(int *sock_in, int *sock_out)
        if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
                dup2(fd, STDIN_FILENO);
                dup2(fd, STDOUT_FILENO);
-               if (fd > STDOUT_FILENO)
+               if (!log_stderr)
+                       dup2(fd, STDERR_FILENO);
+               if (fd > (log_stderr ? STDERR_FILENO : STDOUT_FILENO))
                        close(fd);
        }
        debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out);
@@ -1119,6 +1182,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
        struct sockaddr_storage from;
        socklen_t fromlen;
        pid_t pid;
+       u_char rnd[256];
 
        /* setup fd set for accept */
        fdset = NULL;
@@ -1139,7 +1203,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
                if (received_sighup)
                        sighup_restart();
                if (fdset != NULL)
-                       xfree(fdset);
+                       free(fdset);
                fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS),
                    sizeof(fd_mask));
 
@@ -1188,8 +1252,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
                        *newsock = accept(listen_socks[i],
                            (struct sockaddr *)&from, &fromlen);
                        if (*newsock < 0) {
-                               if (errno != EINTR && errno != EAGAIN &&
-                                   errno != EWOULDBLOCK)
+                               if (errno != EINTR && errno != EWOULDBLOCK &&
+                                   errno != ECONNABORTED && errno != EAGAIN)
                                        error("accept: %.100s",
                                            strerror(errno));
                                if (errno == EMFILE || errno == ENFILE)
@@ -1319,6 +1383,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
                         * from that of the child
                         */
                        arc4random_stir();
+                       arc4random_buf(rnd, sizeof(rnd));
+                       RAND_seed(rnd, sizeof(rnd));
+                       explicit_bzero(rnd, sizeof(rnd));
                }
 
                /* child process check (or debug mode) */
@@ -1340,11 +1407,14 @@ main(int ac, char **av)
        int sock_in = -1, sock_out = -1, newsock = -1;
        const char *remote_ip;
        int remote_port;
-       char *line;
+       char *line, *logfile = NULL;
        int config_s[2] = { -1 , -1 };
+       u_int n;
        u_int64_t ibytes, obytes;
        mode_t new_umask;
        Key *key;
+       Key *pubkey;
+       int keytype;
        Authctxt *authctxt;
        struct connection_info *connection_info = get_connection_info(0, 0);
 
@@ -1377,7 +1447,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:C:dDeiqrtQRT46")) != -1) {
+       while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeE:iqrtQRT46")) != -1) {
                switch (opt) {
                case '4':
                        options.address_family = AF_INET;
@@ -1406,6 +1476,9 @@ main(int ac, char **av)
                case 'D':
                        no_daemon_flag = 1;
                        break;
+               case 'E':
+                       logfile = xstrdup(optarg);
+                       /* FALLTHROUGH */
                case 'e':
                        log_stderr = 1;
                        break;
@@ -1484,7 +1557,7 @@ main(int ac, char **av)
                        if (process_server_config_line(&options, line,
                            "command-line", 0, NULL, NULL) != 0)
                                exit(1);
-                       xfree(line);
+                       free(line);
                        break;
                case '?':
                default:
@@ -1501,8 +1574,15 @@ main(int ac, char **av)
        else
                closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
 
+#ifdef WITH_OPENSSL
        OpenSSL_add_all_algorithms();
+#endif
 
+       /* If requested, redirect the logs to the specified logfile. */
+       if (logfile != NULL) {
+               log_redirect_stderr_to(logfile);
+               free(logfile);
+       }
        /*
         * Force logging to stderr until we have loaded the private host
         * key (unless started from inetd)
@@ -1564,6 +1644,33 @@ main(int ac, char **av)
        if (options.challenge_response_authentication)
                options.kbd_interactive_authentication = 1;
 
+       /* Check that options are sensible */
+       if (options.authorized_keys_command_user == NULL &&
+           (options.authorized_keys_command != NULL &&
+           strcasecmp(options.authorized_keys_command, "none") != 0))
+               fatal("AuthorizedKeysCommand set without "
+                   "AuthorizedKeysCommandUser");
+
+       /*
+        * Check whether there is any path through configured auth methods.
+        * Unfortunately it is not possible to verify this generally before
+        * daemonisation in the presence of Match block, but this catches
+        * and warns for trivial misconfigurations that could break login.
+        */
+       if (options.num_auth_methods != 0) {
+               if ((options.protocol & SSH_PROTO_1))
+                       fatal("AuthenticationMethods is not supported with "
+                           "SSH protocol 1");
+               for (n = 0; n < options.num_auth_methods; n++) {
+                       if (auth2_methods_valid(options.auth_methods[n],
+                           1) == 0)
+                               break;
+               }
+               if (n >= options.num_auth_methods)
+                       fatal("AuthenticationMethods cannot be satisfied by "
+                           "enabled authentication methods");
+       }
+
        /* set default channel AF */
        channel_set_af(options.address_family);
 
@@ -1573,7 +1680,13 @@ main(int ac, char **av)
                exit(1);
        }
 
-       debug("sshd version %.100s", SSH_RELEASE);
+       debug("sshd version %s, %s", SSH_VERSION,
+#ifdef WITH_OPENSSL
+           SSLeay_version(SSLEAY_VERSION)
+#else
+           "without OpenSSL"
+#endif
+       );
 
        /* Store privilege separation user for later use if required. */
        if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
@@ -1581,18 +1694,30 @@ main(int ac, char **av)
                        fatal("Privilege separation user %s does not exist",
                            SSH_PRIVSEP_USER);
        } else {
-               memset(privsep_pw->pw_passwd, 0, strlen(privsep_pw->pw_passwd));
+               explicit_bzero(privsep_pw->pw_passwd,
+                   strlen(privsep_pw->pw_passwd));
                privsep_pw = pwcopy(privsep_pw);
-               xfree(privsep_pw->pw_passwd);
+               free(privsep_pw->pw_passwd);
                privsep_pw->pw_passwd = xstrdup("*");
        }
        endpwent();
 
-       /* load private host keys */
+       /* load host keys */
        sensitive_data.host_keys = xcalloc(options.num_host_key_files,
            sizeof(Key *));
-       for (i = 0; i < options.num_host_key_files; i++)
+       sensitive_data.host_pubkeys = xcalloc(options.num_host_key_files,
+           sizeof(Key *));
+       for (i = 0; i < options.num_host_key_files; i++) {
                sensitive_data.host_keys[i] = NULL;
+               sensitive_data.host_pubkeys[i] = NULL;
+       }
+
+       if (options.host_key_agent) {
+               if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
+                       setenv(SSH_AUTHSOCKET_ENV_NAME,
+                           options.host_key_agent, 1);
+               have_agent = ssh_agent_present();
+       }
 
        for (i = 0; i < options.num_host_key_files; i++) {
                key = key_load_private(options.host_key_files[i], "", NULL);
@@ -1611,14 +1736,26 @@ main(int ac, char **av)
                                continue;
                        }
                }
+               pubkey = key_load_public(options.host_key_files[i], NULL);
                sensitive_data.host_keys[i] = key;
-               if (key == NULL) {
+               sensitive_data.host_pubkeys[i] = pubkey;
+
+               if (key == NULL && pubkey != NULL && pubkey->type != KEY_RSA1 &&
+                   have_agent) {
+                       debug("will rely on agent for hostkey %s",
+                           options.host_key_files[i]);
+                       keytype = pubkey->type;
+               } else if (key != NULL) {
+                       keytype = key->type;
+               } else {
                        error("Could not load host key: %s",
                            options.host_key_files[i]);
                        sensitive_data.host_keys[i] = NULL;
+                       sensitive_data.host_pubkeys[i] = NULL;
                        continue;
                }
-               switch (key->type) {
+
+               switch (keytype) {
                case KEY_RSA1:
                        sensitive_data.ssh1_host_key = key;
                        sensitive_data.have_ssh1_key = 1;
@@ -1626,11 +1763,12 @@ main(int ac, char **av)
                case KEY_RSA:
                case KEY_DSA:
                case KEY_ECDSA:
+               case KEY_ED25519:
                        sensitive_data.have_ssh2_key = 1;
                        break;
                }
-               debug("private host key: #%d type %d %s", i, key->type,
-                   key_type(key));
+               debug("private host key: #%d type %d %s", i, keytype,
+                   key_type(key ? key : pubkey));
        }
        if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
                logit("Disabling protocol version 1. Could not load host key");
@@ -1685,6 +1823,8 @@ main(int ac, char **av)
                debug("host certificate: #%d type %d %s", j, key->type,
                    key_type(key));
        }
+
+#ifdef WITH_SSH1
        /* Check certain values for sanity. */
        if (options.protocol & SSH_PROTO_1) {
                if (options.server_key_bits < 512 ||
@@ -1709,6 +1849,7 @@ main(int ac, char **av)
                            options.server_key_bits);
                }
        }
+#endif
 
        if (use_privsep) {
                struct stat st;
@@ -1792,12 +1933,10 @@ main(int ac, char **av)
        /* Reinitialize the log (because of the fork above). */
        log_init(__progname, options.log_level, options.log_facility, log_stderr);
 
-       /* Initialize the random number generator. */
-       arc4random_stir();
-
        /* Chdir to the root directory so that the current disk can be
           unmounted if desired. */
-       chdir("/");
+       if (chdir("/") == -1)
+               error("chdir(\"/\"): %s", strerror(errno));
 
        /* ignore SIGPIPE */
        signal(SIGPIPE, SIG_IGN);
@@ -1874,13 +2013,14 @@ main(int ac, char **av)
                dup2(STDIN_FILENO, STDOUT_FILENO);
                if (startup_pipe == -1)
                        close(REEXEC_STARTUP_PIPE_FD);
-               else
+               else if (startup_pipe != REEXEC_STARTUP_PIPE_FD) {
                        dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD);
+                       close(startup_pipe);
+                       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);
 
@@ -1891,8 +2031,6 @@ main(int ac, char **av)
                    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) {
@@ -1954,27 +2092,11 @@ main(int ac, char **av)
 #ifdef SSH_AUDIT_EVENTS
        audit_connection_from(remote_ip, remote_port);
 #endif
-#ifdef LIBWRAP
-       allow_severity = options.log_facility|LOG_INFO;
-       deny_severity = options.log_facility|LOG_WARNING;
-       /* 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);
-               fromhost(&req);
-
-               if (!hosts_access(&req)) {
-                       debug("Connection refused by tcp wrapper");
-                       refuse(&req);
-                       /* NOTREACHED */
-                       fatal("libwrap refuse returns");
-               }
-       }
-#endif /* LIBWRAP */
 
        /* Log the connection. */
-       verbose("Connection from %.500s port %d", remote_ip, remote_port);
+       verbose("Connection from %s port %d on %s port %d",
+           remote_ip, remote_port,
+           get_local_ipaddr(sock_in), get_local_port());
 
        /* set the HPN options for the child */
        channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
@@ -2011,9 +2133,11 @@ main(int ac, char **av)
        buffer_init(&loginmsg);
        auth_debug_reset();
 
-       if (use_privsep)
+       if (use_privsep) {
                if (privsep_preauth(authctxt) == 1)
                        goto authenticated;
+       } else if (compat20 && have_agent)
+               auth_conn = ssh_get_authentication_connection();
 
        /* perform the key exchange */
        /* authenticate user and start session */
@@ -2021,8 +2145,12 @@ main(int ac, char **av)
                do_ssh2_kex();
                do_authentication2(authctxt);
        } else {
+#ifdef WITH_SSH1
                do_ssh1_kex();
                do_authentication(authctxt);
+#else
+               fatal("ssh1 not supported");
+#endif
        }
        /*
         * If we use privilege separation, the unprivileged child transfers
@@ -2106,6 +2234,7 @@ main(int ac, char **av)
        exit(0);
 }
 
+#ifdef WITH_SSH1
 /*
  * Decrypt session_key_int using our private server key and private host key
  * (key with larger modulus first).
@@ -2129,10 +2258,10 @@ ssh1_session_key(BIGNUM *session_key_int)
                            SSH_KEY_BITS_RESERVED);
                }
                if (rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.server_key->rsa) <= 0)
+                   sensitive_data.server_key->rsa) != 0)
                        rsafail++;
                if (rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.ssh1_host_key->rsa) <= 0)
+                   sensitive_data.ssh1_host_key->rsa) != 0)
                        rsafail++;
        } else {
                /* Host key has bigger modulus (or they are equal). */
@@ -2147,14 +2276,15 @@ ssh1_session_key(BIGNUM *session_key_int)
                            SSH_KEY_BITS_RESERVED);
                }
                if (rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.ssh1_host_key->rsa) < 0)
+                   sensitive_data.ssh1_host_key->rsa) != 0)
                        rsafail++;
                if (rsa_private_decrypt(session_key_int, session_key_int,
-                   sensitive_data.server_key->rsa) < 0)
+                   sensitive_data.server_key->rsa) != 0)
                        rsafail++;
        }
        return (rsafail);
 }
+
 /*
  * SSH1 key exchange
  */
@@ -2267,7 +2397,7 @@ do_ssh1_kex(void)
                            get_remote_ipaddr(), len, (u_long)sizeof(session_key));
                        rsafail++;
                } else {
-                       memset(session_key, 0, sizeof(session_key));
+                       explicit_bzero(session_key, sizeof(session_key));
                        BN_bn2bin(session_key_int,
                            session_key + sizeof(session_key) - len);
 
@@ -2286,21 +2416,27 @@ do_ssh1_kex(void)
        if (rsafail) {
                int bytes = BN_num_bytes(session_key_int);
                u_char *buf = xmalloc(bytes);
-               MD5_CTX md;
+               struct ssh_digest_ctx *md;
 
                logit("do_connection: generating a fake encryption key");
                BN_bn2bin(session_key_int, buf);
-               MD5_Init(&md);
-               MD5_Update(&md, buf, bytes);
-               MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
-               MD5_Final(session_key, &md);
-               MD5_Init(&md);
-               MD5_Update(&md, session_key, 16);
-               MD5_Update(&md, buf, bytes);
-               MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
-               MD5_Final(session_key + 16, &md);
-               memset(buf, 0, bytes);
-               xfree(buf);
+               if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
+                   ssh_digest_update(md, buf, bytes) < 0 ||
+                   ssh_digest_update(md, sensitive_data.ssh1_cookie,
+                   SSH_SESSION_KEY_LENGTH) < 0 ||
+                   ssh_digest_final(md, session_key, sizeof(session_key)) < 0)
+                       fatal("%s: md5 failed", __func__);
+               ssh_digest_free(md);
+               if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
+                   ssh_digest_update(md, session_key, 16) < 0 ||
+                   ssh_digest_update(md, sensitive_data.ssh1_cookie,
+                   SSH_SESSION_KEY_LENGTH) < 0 ||
+                   ssh_digest_final(md, session_key + 16,
+                   sizeof(session_key) - 16) < 0)
+                       fatal("%s: md5 failed", __func__);
+               ssh_digest_free(md);
+               explicit_bzero(buf, bytes);
+               free(buf);
                for (i = 0; i < 16; i++)
                        session_id[i] = session_key[i] ^ session_key[i + 16];
        }
@@ -2317,7 +2453,7 @@ do_ssh1_kex(void)
        packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
 
        /* Destroy our copy of the session key.  It is no longer needed. */
-       memset(session_key, 0, sizeof(session_key));
+       explicit_bzero(session_key, sizeof(session_key));
 
        debug("Received session key; encryption turned on.");
 
@@ -2326,6 +2462,24 @@ do_ssh1_kex(void)
        packet_send();
        packet_write_wait();
 }
+#endif
+
+void
+sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
+    u_char *data, u_int dlen)
+{
+       if (privkey) {
+               if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0))
+                       fatal("%s: key_sign failed", __func__);
+       } else if (use_privsep) {
+               if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0)
+                       fatal("%s: pubkey_sign failed", __func__);
+       } else {
+               if (ssh_agent_sign(auth_conn, pubkey, signature, slen, data,
+                   dlen))
+                       fatal("%s: ssh_agent_sign failed", __func__);
+       }
+}
 
 /*
  * SSH2 key exchange: diffie-hellman-group1-sha1
@@ -2333,6 +2487,7 @@ do_ssh1_kex(void)
 static void
 do_ssh2_kex(void)
 {
+       char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
        Kex *kex;
 
        myflag++;
@@ -2364,21 +2519,33 @@ do_ssh2_kex(void)
        if (options.kex_algorithms != NULL)
                myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
 
-       myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
+       myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
+           myproposal[PROPOSAL_KEX_ALGS]);
+
+       if (options.rekey_limit || options.rekey_interval)
+               packet_set_rekey_limits((u_int32_t)options.rekey_limit,
+                   (time_t)options.rekey_interval);
+
+       myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
+           list_hostkey_types());
 
        /* start key exchange */
        kex = kex_setup(myproposal);
+#ifdef WITH_OPENSSL
        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->kex[KEX_DH_GEX_SHA256] = kexgex_server;
        kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
+#endif
+       kex->kex[KEX_C25519_SHA256] = kexc25519_server;
        kex->server = 1;
        kex->client_version_string=client_version_string;
        kex->server_version_string=server_version_string;
        kex->load_host_public_key=&get_hostkey_public_by_type;
        kex->load_host_private_key=&get_hostkey_private_by_type;
        kex->host_key_index=&get_hostkey_index;
+       kex->sign = sshd_hostkey_sign;
 
        xxx_kex = kex;
 
@@ -2403,7 +2570,8 @@ cleanup_exit(int i)
 {
        if (the_authctxt) {
                do_cleanup(the_authctxt);
-               if (use_privsep && privsep_is_preauth && pmonitor->m_pid > 1) {
+               if (use_privsep && privsep_is_preauth &&
+                   pmonitor != NULL && pmonitor->m_pid > 1) {
                        debug("Killing privsep child %d", pmonitor->m_pid);
                        if (kill(pmonitor->m_pid, SIGKILL) != 0 &&
                            errno != ESRCH)