]> andersk Git - openssh.git/commitdiff
- provos@cvs.openbsd.org 2002/03/18 17:50:31
authormouring <mouring>
Fri, 22 Mar 2002 02:30:41 +0000 (02:30 +0000)
committermouring <mouring>
Fri, 22 Mar 2002 02:30:41 +0000 (02:30 +0000)
     [auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c auth-skey.c auth.h
      auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c kexgex.c servconf.c
      session.h servconf.h serverloop.c session.c sshd.c]
     integrate privilege separated openssh; its turned off by default for now.
     work done by me and markus@

applied, but outside of ensure that smaller code bits migrated with
their owners.. no work was tried to 'fix' it to work. =)  Later project!

29 files changed:
ChangeLog
Makefile.in
auth-bsdauth.c
auth-options.c
auth-rh-rsa.c
auth-rsa.c
auth-skey.c
auth.h
auth1.c
auth2-chall.c
auth2.c
kex.c
kex.h
kexdh.c
kexgex.c
monitor.c [new file with mode: 0644]
monitor.h [new file with mode: 0644]
monitor_fdpass.c [new file with mode: 0644]
monitor_fdpass.h [new file with mode: 0644]
monitor_mm.c [new file with mode: 0644]
monitor_mm.h [new file with mode: 0644]
monitor_wrap.c [new file with mode: 0644]
monitor_wrap.h [new file with mode: 0644]
servconf.c
servconf.h
serverloop.c
session.c
session.h
sshd.c

index 593b30c05ec37f537da52f1b7c43ed163f5b6098..fe1c466ffef9fc2cc8d6a48f2836a8b68e266221 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
    - provos@cvs.openbsd.org 2002/03/18 17:31:54
      [compress.c]
      export compression streams for ssh-privsep
+   - provos@cvs.openbsd.org 2002/03/18 17:50:31
+     [auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c auth-skey.c auth.h
+      auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c kexgex.c servconf.c
+      session.h servconf.h serverloop.c session.c sshd.c]
+     integrate privilege separated openssh; its turned off by default for now.
+     work done by me and markus@
 
 20020317
  - (tim) [configure.ac] Assume path given with --with-pid-dir=PATH is wanted,
index 5bc3cb0fd31d9a6efcae08ea88e2428b6e7950ba..81a9cfc52724321606edd8a7b80e99cb75c7a760 100644 (file)
@@ -50,11 +50,11 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
 
 TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
 
-SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o monitor_mm.o monitor.o
 
 MANPAGES       = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out
 MANPAGES_IN    = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1
index b70d48f20e02f1024ae93e2c94691d7f03d9b7b2..fa06732cc2e63eda04e0a669ba16f7537271ab4d 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "includes.h"
-RCSID("$OpenBSD: auth-bsdauth.c,v 1.2 2001/12/19 07:18:56 deraadt Exp $");
+RCSID("$OpenBSD: auth-bsdauth.c,v 1.3 2002/03/18 17:50:31 provos Exp $");
 
 #ifdef BSD_AUTH
 #include "xmalloc.h"
 #include "auth.h"
 #include "log.h"
+#include "monitor_wrap.h"
 
 static void *
 bsdauth_init_ctx(Authctxt *authctxt)
@@ -35,7 +36,7 @@ bsdauth_init_ctx(Authctxt *authctxt)
        return authctxt;
 }
 
-static int
+int
 bsdauth_query(void *ctx, char **name, char **infotxt,
    u_int *numprompts, char ***prompts, u_int **echo_on)
 {
@@ -76,7 +77,7 @@ bsdauth_query(void *ctx, char **name, char **infotxt,
        return 0;
 }
 
-static int
+int
 bsdauth_respond(void *ctx, u_int numresponses, char **responses)
 {
        Authctxt *authctxt = ctx;
@@ -113,4 +114,12 @@ KbdintDevice bsdauth_device = {
        bsdauth_respond,
        bsdauth_free_ctx
 };
+
+KbdintDevice mm_bsdauth_device = {
+       "bsdauth",
+       bsdauth_init_ctx,
+       mm_bsdauth_query,
+       mm_bsdauth_respond,
+       bsdauth_free_ctx
+};
 #endif
index 8df6a6dfcabbd910313e620f770503c02432b2ed..48be6d8e0f46ea06e4aa69a4c9c8403674b4802b 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $");
+RCSID("$OpenBSD: auth-options.c,v 1.22 2002/03/18 17:50:31 provos Exp $");
 
 #include "packet.h"
 #include "xmalloc.h"
@@ -20,7 +20,13 @@ RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $");
 #include "channels.h"
 #include "auth-options.h"
 #include "servconf.h"
+#include "bufaux.h"
 #include "misc.h"
+#include "monitor_wrap.h"
+
+/* Debugging messages */
+Buffer auth_debug;
+int auth_debug_init;
 
 /* Flags set authorized_keys flags */
 int no_port_forwarding_flag = 0;
@@ -36,9 +42,28 @@ struct envstring *custom_environment = NULL;
 
 extern ServerOptions options;
 
+void
+auth_send_debug(Buffer *m)
+{
+       char *msg;
+
+       while (buffer_len(m)) {
+               msg = buffer_get_string(m, NULL);
+               packet_send_debug("%s", msg);
+               xfree(msg);
+       }
+}
+
 void
 auth_clear_options(void)
 {
+       if (auth_debug_init)
+               buffer_clear(&auth_debug);
+       else {
+               buffer_init(&auth_debug);
+               auth_debug_init = 1;
+       }
+
        no_agent_forwarding_flag = 0;
        no_port_forwarding_flag = 0;
        no_pty_flag = 0;
@@ -63,6 +88,7 @@ auth_clear_options(void)
 int
 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
 {
+       char tmp[1024];
        const char *cp;
        int i;
 
@@ -75,28 +101,32 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
        while (*opts && *opts != ' ' && *opts != '\t') {
                cp = "no-port-forwarding";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       packet_send_debug("Port forwarding disabled.");
+                       snprintf(tmp, sizeof(tmp), "Port forwarding disabled.");
+                       buffer_put_cstring(&auth_debug, tmp);
                        no_port_forwarding_flag = 1;
                        opts += strlen(cp);
                        goto next_option;
                }
                cp = "no-agent-forwarding";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       packet_send_debug("Agent forwarding disabled.");
+                       snprintf(tmp, sizeof(tmp), "Agent forwarding disabled.");
+                       buffer_put_cstring(&auth_debug, tmp);
                        no_agent_forwarding_flag = 1;
                        opts += strlen(cp);
                        goto next_option;
                }
                cp = "no-X11-forwarding";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       packet_send_debug("X11 forwarding disabled.");
+                       snprintf(tmp, sizeof(tmp), "X11 forwarding disabled.");
+                       buffer_put_cstring(&auth_debug, tmp);
                        no_x11_forwarding_flag = 1;
                        opts += strlen(cp);
                        goto next_option;
                }
                cp = "no-pty";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       packet_send_debug("Pty allocation disabled.");
+                       snprintf(tmp, sizeof(tmp), "Pty allocation disabled.");
+                       buffer_put_cstring(&auth_debug, tmp);
                        no_pty_flag = 1;
                        opts += strlen(cp);
                        goto next_option;
@@ -119,14 +149,16 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        if (!*opts) {
                                debug("%.100s, line %lu: missing end quote",
                                    file, linenum);
-                               packet_send_debug("%.100s, line %lu: missing end quote",
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote",
                                    file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(forced_command);
                                forced_command = NULL;
                                goto bad_option;
                        }
                        forced_command[i] = 0;
-                       packet_send_debug("Forced command: %.900s", forced_command);
+                       snprintf(tmp, sizeof(tmp), "Forced command: %.900s", forced_command);
+                       buffer_put_cstring(&auth_debug, tmp);
                        opts++;
                        goto next_option;
                }
@@ -151,13 +183,15 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        if (!*opts) {
                                debug("%.100s, line %lu: missing end quote",
                                    file, linenum);
-                               packet_send_debug("%.100s, line %lu: missing end quote",
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote",
                                    file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(s);
                                goto bad_option;
                        }
                        s[i] = 0;
-                       packet_send_debug("Adding to environment: %.900s", s);
+                       snprintf(tmp, sizeof(tmp), "Adding to environment: %.900s", s);
+                       buffer_put_cstring(&auth_debug, tmp);
                        debug("Adding to environment: %.900s", s);
                        opts++;
                        new_envstring = xmalloc(sizeof(struct envstring));
@@ -188,8 +222,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        if (!*opts) {
                                debug("%.100s, line %lu: missing end quote",
                                    file, linenum);
-                               packet_send_debug("%.100s, line %lu: missing end quote",
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote",
                                    file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(patterns);
                                goto bad_option;
                        }
@@ -202,9 +237,11 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                                    "correct key but not from a permitted "
                                    "host (host=%.200s, ip=%.200s).",
                                    pw->pw_name, remote_host, remote_ip);
-                               packet_send_debug("Your host '%.200s' is not "
+                               snprintf(tmp, sizeof(tmp),
+                                   "Your host '%.200s' is not "
                                    "permitted to use this key for login.",
                                    remote_host);
+                               buffer_put_cstring(&auth_debug, tmp);
                                /* deny access */
                                return 0;
                        }
@@ -233,8 +270,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        if (!*opts) {
                                debug("%.100s, line %lu: missing end quote",
                                    file, linenum);
-                               packet_send_debug("%.100s, line %lu: missing end quote",
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote",
                                    file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(patterns);
                                goto bad_option;
                        }
@@ -244,16 +282,18 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                            sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
                                debug("%.100s, line %lu: Bad permitopen specification "
                                    "<%.100s>", file, linenum, patterns);
-                               packet_send_debug("%.100s, line %lu: "
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: "
                                    "Bad permitopen specification", file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(patterns);
                                goto bad_option;
                        }
                        if ((port = a2port(sport)) == 0) {
                                debug("%.100s, line %lu: Bad permitopen port <%.100s>",
                                    file, linenum, sport);
-                               packet_send_debug("%.100s, line %lu: "
+                               snprintf(tmp, sizeof(tmp), "%.100s, line %lu: "
                                    "Bad permitopen port", file, linenum);
+                               buffer_put_cstring(&auth_debug, tmp);
                                xfree(patterns);
                                goto bad_option;
                        }
@@ -276,14 +316,24 @@ next_option:
                opts++;
                /* Process the next option. */
        }
+
+       if (!use_privsep)
+               auth_send_debug(&auth_debug);
+
        /* grant access */
        return 1;
 
 bad_option:
        log("Bad options in %.100s file, line %lu: %.50s",
            file, linenum, opts);
-       packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
+       snprintf(tmp, sizeof(tmp),
+           "Bad options in %.100s file, line %lu: %.50s",
            file, linenum, opts);
+       buffer_put_cstring(&auth_debug, tmp);
+
+       if (!use_privsep)
+               auth_send_debug(&auth_debug);
+
        /* deny access */
        return 0;
 }
index 2a88e18b35ec1199b1451ecd40bdbd34a11c0c5c..c940ec581f005e6486f96a92f57a19c133070f46 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth-rh-rsa.c,v 1.31 2002/03/16 17:22:09 markus Exp $");
+RCSID("$OpenBSD: auth-rh-rsa.c,v 1.32 2002/03/18 17:50:31 provos Exp $");
 
 #include "packet.h"
 #include "uidswap.h"
@@ -25,6 +25,8 @@ RCSID("$OpenBSD: auth-rh-rsa.c,v 1.31 2002/03/16 17:22:09 markus Exp $");
 #include "auth.h"
 #include "canohost.h"
 
+#include "monitor_wrap.h"
+
 /* import */
 extern ServerOptions options;
 
@@ -69,7 +71,7 @@ auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key)
        chost = (char *)get_canonical_hostname(options.verify_reverse_mapping);
        debug("Rhosts RSA authentication: canonical host %.900s", chost);
 
-       if (!auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key)) {
+       if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) {
                debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
                packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
                return 0;
index ff9bf3b64207d5cd34dbf7e0f245d2b19fb03e9b..9c5d484b19ebddd8ed744d9e0398ffa8653959d2 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth-rsa.c,v 1.51 2002/03/14 16:56:33 markus Exp $");
+RCSID("$OpenBSD: auth-rsa.c,v 1.52 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/md5.h>
@@ -32,6 +32,7 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.51 2002/03/14 16:56:33 markus Exp $");
 #include "servconf.h"
 #include "auth.h"
 #include "hostfile.h"
+#include "monitor_wrap.h"
 
 /* import */
 extern ServerOptions options;
@@ -52,7 +53,7 @@ extern u_char session_id[16];
  * description of the options.
  */
 
-static BIGNUM *
+BIGNUM *
 auth_rsa_generate_challenge(Key *key)
 {
        BIGNUM *challenge;
@@ -70,7 +71,7 @@ auth_rsa_generate_challenge(Key *key)
        return challenge;
 }
 
-static int
+int
 auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
 {
        u_char buf[32], mdbuf[16];
@@ -113,7 +114,7 @@ auth_rsa_challenge_dialog(Key *key)
        if ((encrypted_challenge = BN_new()) == NULL)
                fatal("auth_rsa_challenge_dialog: BN_new() failed");
 
-       challenge = auth_rsa_generate_challenge(key);
+       challenge = PRIVSEP(auth_rsa_generate_challenge(key));
 
        /* Encrypt the challenge with the public key. */
        rsa_public_encrypt(encrypted_challenge, challenge, key->rsa);
@@ -131,7 +132,7 @@ auth_rsa_challenge_dialog(Key *key)
                response[i] = packet_get_char();
        packet_check_eom();
 
-       success = auth_rsa_verify_response(key, challenge, response);
+       success = PRIVSEP(auth_rsa_verify_response(key, challenge, response));
        BN_clear_free(challenge);
        return (success);
 }
@@ -141,11 +142,11 @@ auth_rsa_challenge_dialog(Key *key)
  * return key if login is allowed, NULL otherwise
  */
 
-static int
+int
 auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
 {
        char line[8192], *file;
-       int allowed;
+       int allowed = 0;
        u_int bits;
        FILE *f;
        u_long linenum = 0;
@@ -284,7 +285,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
        if (pw == NULL)
                return 0;
 
-       if (auth_rsa_key_allowed(pw, client_n, &key) == 0) {
+       if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) {
                auth_clear_options();
                return (0);
        }
index df19f75072d17190f078f22fc10de50a6406ad05..e897d18756e5a12da97870f414174f488107c5ea 100644 (file)
@@ -22,7 +22,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "includes.h"
-RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $");
+RCSID("$OpenBSD: auth-skey.c,v 1.17 2002/03/18 17:50:31 provos Exp $");
 
 #ifdef SKEY
 
@@ -30,6 +30,7 @@ RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $");
 
 #include "xmalloc.h"
 #include "auth.h"
+#include "monitor_wrap.h"
 
 static void *
 skey_init_ctx(Authctxt *authctxt)
@@ -37,8 +38,6 @@ skey_init_ctx(Authctxt *authctxt)
        return authctxt;
 }
 
-#define PROMPT "\nS/Key Password: "
-
 static int
 skey_query(void *ctx, char **name, char **infotxt,
     u_int* numprompts, char ***prompts, u_int **echo_on)
@@ -58,10 +57,10 @@ skey_query(void *ctx, char **name, char **infotxt,
        *echo_on = xmalloc(*numprompts * sizeof(u_int));
        (*echo_on)[0] = 0;
 
-       len = strlen(challenge) + strlen(PROMPT) + 1;
+       len = strlen(challenge) + strlen(SKEY_PROMPT) + 1;
        p = xmalloc(len);
        strlcpy(p, challenge, len);
-       strlcat(p, PROMPT, len);
+       strlcat(p, SKEY_PROMPT, len);
        (*prompts)[0] = p;
 
        return 0;
@@ -93,4 +92,12 @@ KbdintDevice skey_device = {
        skey_respond,
        skey_free_ctx
 };
+
+KbdintDevice mm_skey_device = {
+       "skey",
+       skey_init_ctx,
+       mm_skey_query,
+       mm_skey_respond,
+       skey_free_ctx
+};
 #endif /* SKEY */
diff --git a/auth.h b/auth.h
index bdfdf1c54117f2438879db454ec0d59136c8323f..3e4a55010f92214212f8d67f073b003b9c26f71f 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
-/*     $OpenBSD: auth.h,v 1.33 2002/03/18 01:12:14 provos Exp $        */
+/*     $OpenBSD: auth.h,v 1.34 2002/03/18 17:50:31 provos Exp $        */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -129,6 +129,8 @@ void        auth_log(Authctxt *, int, char *, char *);
 void   userauth_finish(Authctxt *, int, char *);
 int    auth_root_allowed(char *);
 
+void   privsep_challenge_enable(void);
+
 int    auth2_challenge(Authctxt *, char *);
 void   auth2_challenge_stop(Authctxt *);
 
@@ -155,4 +157,5 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *,
 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
 #define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
 
+#define SKEY_PROMPT "\nS/Key Password: "
 #endif
diff --git a/auth1.c b/auth1.c
index 4c295215f20c549a4c10be5594d5eb2d99d1efba..ca288958e71780f128424c9ae039fd20dba5b8ed 100644 (file)
--- a/auth1.c
+++ b/auth1.c
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.37 2002/03/18 01:12:14 provos Exp $");
+RCSID("$OpenBSD: auth1.c,v 1.38 2002/03/18 17:50:31 provos Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -26,6 +26,7 @@ RCSID("$OpenBSD: auth1.c,v 1.37 2002/03/18 01:12:14 provos Exp $");
 #include "session.h"
 #include "misc.h"
 #include "uidswap.h"
+#include "monitor_wrap.h"
 
 /* import */
 extern ServerOptions options;
@@ -89,7 +90,7 @@ do_authloop(Authctxt *authctxt)
 #elif defined(HAVE_OSF_SIA)
            0) {
 #else
-           auth_password(authctxt, "")) {
+           PRIVSEP(auth_password(authctxt, ""))) {
 #endif
                auth_log(authctxt, 1, "without authentication", "");
                return;
@@ -253,9 +254,8 @@ do_authloop(Authctxt *authctxt)
                        /* Do SIA auth with password */
                        authenticated = auth_sia_password(authctxt->user, 
                            password);
-#else /* !USE_PAM && !HAVE_OSF_SIA */
                        /* Try authentication with the password. */
-                       authenticated = auth_password(authctxt, password);
+                       authenticated = PRIVSEP(auth_password(authctxt, password));
 #endif /* USE_PAM */
 
                        memset(password, 0, strlen(password));
@@ -359,7 +359,7 @@ Authctxt *
 do_authentication(void)
 {
        Authctxt *authctxt;
-       struct passwd *pw;
+       struct passwd *pw = NULL, *pwent;
        u_int ulen;
        char *p, *user, *style = NULL;
 
@@ -382,17 +382,22 @@ do_authentication(void)
        authctxt->style = style;
 
        /* Verify that the user is a valid user. */
-       pw = getpwnamallow(user);
-       if (pw) {
+       pwent = PRIVSEP(getpwnamallow(user));
+       if (pwent) {
                authctxt->valid = 1;
-               pw = pwcopy(pw);
+               pw = pwcopy(pwent);
        } else {
                debug("do_authentication: illegal user %s", user);
                pw = NULL;
        }
+       /* Free memory */
+       if (use_privsep && pwent != NULL)
+               pwfree(pwent);
+
        authctxt->pw = pw;
 
-       setproctitle("%s", pw ? user : "unknown");
+       setproctitle("%s%s", pw ? user : "unknown",
+           use_privsep ? " [net]" : "");
 
 #ifdef USE_PAM
        start_pam(pw == NULL ? "NOUSER" : user);
@@ -403,7 +408,7 @@ do_authentication(void)
         * the server. (Unless you are running Windows)
         */
 #ifndef HAVE_CYGWIN
-       if (getuid() != 0 && pw && pw->pw_uid != getuid())
+       if (!use_privsep && getuid() != 0 && pw && pw->pw_uid != getuid())
                packet_disconnect("Cannot change user when server not running as root.");
 #endif
 
index 9f1d932756b3283e6a59aa16949c12db438edc34..38f955a022cf562b4df26c8c12f02b01c2e701c9 100644 (file)
@@ -23,7 +23,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "includes.h"
-RCSID("$OpenBSD: auth2-chall.c,v 1.16 2002/01/13 17:57:37 markus Exp $");
+RCSID("$OpenBSD: auth2-chall.c,v 1.17 2002/03/18 17:50:31 provos Exp $");
 
 #include "ssh2.h"
 #include "auth.h"
@@ -310,3 +310,22 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
        userauth_finish(authctxt, authenticated, method);
        xfree(method);
 }
+
+void
+privsep_challenge_enable(void)
+{
+#ifdef BSD_AUTH
+       extern KbdintDevice mm_bsdauth_device;
+#endif
+#ifdef SKEY
+       extern KbdintDevice mm_skey_device;
+#endif
+       /* As long as SSHv1 has devices[0] hard coded this is fine */
+#ifdef BSD_AUTH
+       devices[0] = &mm_bsdauth_device;
+#else
+#ifdef SKEY
+       devices[0] = &mm_skey_device;
+#endif
+#endif
+}
diff --git a/auth2.c b/auth2.c
index b57fda216de8068b4f7b970f407fdb43c3e9b5bd..9bfcde5c1de7304de5db396c09a4c4d9eb6f8ac0 100644 (file)
--- a/auth2.c
+++ b/auth2.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.87 2002/03/18 01:12:14 provos Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.88 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/evp.h>
 
@@ -51,13 +51,14 @@ RCSID("$OpenBSD: auth2.c,v 1.87 2002/03/18 01:12:14 provos Exp $");
 #include "hostfile.h"
 #include "canohost.h"
 #include "match.h"
+#include "monitor_wrap.h"
 
 /* import */
 extern ServerOptions options;
 extern u_char *session_id2;
 extern int session_id2_len;
 
-static Authctxt        *x_authctxt = NULL;
+Authctxt *x_authctxt = NULL;
 static int one = 1;
 
 typedef struct Authmethod Authmethod;
@@ -75,8 +76,8 @@ static void input_userauth_request(int, u_int32_t, void *);
 /* helper */
 static Authmethod *authmethod_lookup(const char *);
 static char *authmethods_get(void);
-static int user_key_allowed(struct passwd *, Key *);
-static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
+int user_key_allowed(struct passwd *, Key *);
+int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
 
 /* auth */
 static void userauth_banner(void);
@@ -185,7 +186,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
        if (authctxt->attempt++ == 0) {
                /* setup auth context */
                struct passwd *pw = NULL;
-               pw = getpwnamallow(user);
+               pw = PRIVSEP(getpwnamallow(user));
                if (pw && strcmp(service, "ssh-connection")==0) {
                        authctxt->pw = pwcopy(pw);
                        authctxt->valid = 1;
@@ -199,10 +200,18 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                        start_pam("NOUSER");
 #endif
                }
-               setproctitle("%s", pw ? user : "unknown");
+               /* Free memory */
+               if (use_privsep && pw != NULL)
+                       pwfree(pw);
+
+               setproctitle("%s%s", pw ? user : "unknown",
+                   use_privsep ? " [net]" : "");
                authctxt->user = xstrdup(user);
                authctxt->service = xstrdup(service);
                authctxt->style = style ? xstrdup(style) : NULL;
+
+               if (use_privsep)
+                       mm_inform_authserv(service, style);
        } else if (strcmp(user, authctxt->user) != 0 ||
            strcmp(service, authctxt->service) != 0) {
                packet_disconnect("Change of username or service not allowed: "
@@ -333,7 +342,7 @@ userauth_none(Authctxt *authctxt)
 #elif defined(HAVE_OSF_SIA)
        return 0;
 #else /* !HAVE_OSF_SIA && !USE_PAM */
-       return auth_password(authctxt, "");
+       return PRIVSEP(auth_password(authctxt, ""));
 #endif /* USE_PAM */
 }
 
@@ -358,7 +367,7 @@ userauth_passwd(Authctxt *authctxt)
 #elif defined(HAVE_OSF_SIA)
            auth_sia_password(authctxt->user, password) == 1)
 #else /* !USE_PAM && !HAVE_OSF_SIA */
-           auth_password(authctxt, password) == 1)
+           PRIVSEP(auth_password(authctxt, password)) == 1)
 #endif /* USE_PAM */
                authenticated = 1;
        memset(password, 0, len);
@@ -468,8 +477,10 @@ userauth_pubkey(Authctxt *authctxt)
                buffer_dump(&b);
 #endif
                /* test for correct signature */
-               if (user_key_allowed(authctxt->pw, key) &&
-                   key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+               authenticated = 0;
+               if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+                   PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
+                               buffer_len(&b))) == 1)
                        authenticated = 1;
                buffer_clear(&b);
                xfree(sig);
@@ -485,7 +496,7 @@ userauth_pubkey(Authctxt *authctxt)
                 * if a user is not allowed to login. is this an
                 * issue? -markus
                 */
-               if (user_key_allowed(authctxt->pw, key)) {
+               if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
                        packet_start(SSH2_MSG_USERAUTH_PK_OK);
                        packet_put_string(pkalg, alen);
                        packet_put_string(pkblob, blen);
@@ -573,8 +584,10 @@ userauth_hostbased(Authctxt *authctxt)
        buffer_dump(&b);
 #endif
        /* test for allowed key and correct signature */
-       if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
-           key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+       authenticated = 0;
+       if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
+           PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
+                       buffer_len(&b))) == 1)
                authenticated = 1;
 
        buffer_clear(&b);
@@ -731,7 +744,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
 }
 
 /* check whether given key is in .ssh/authorized_keys* */
-static int
+int
 user_key_allowed(struct passwd *pw, Key *key)
 {
        int success;
@@ -751,7 +764,7 @@ user_key_allowed(struct passwd *pw, Key *key)
 }
 
 /* return 1 if given hostkey is allowed */
-static int
+int
 hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
     Key *key)
 {
diff --git a/kex.c b/kex.c
index bf8fd95b4a289a3f0ea0bffdc0ced3d88f8b1509..8097ab0f26348633d9e6bab58298b9d96b27995c 100644 (file)
--- a/kex.c
+++ b/kex.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $");
+RCSID("$OpenBSD: kex.c,v 1.48 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/crypto.h>
 
@@ -40,9 +40,15 @@ RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $");
 #include "mac.h"
 #include "match.h"
 #include "dispatch.h"
+#include "monitor.h"
 
 #define KEX_COOKIE_LEN 16
 
+/* Use privilege separation for sshd */
+int use_privsep;
+struct monitor *monitor;
+
+
 /* prototype */
 static void kex_kexinit_finish(Kex *);
 static void kex_choose_conf(Kex *);
diff --git a/kex.h b/kex.h
index 755bf332aa40b52ddd26abc31a82e626a4a63a58..2d3523a36339403db18c7da00226073942b4ddbf 100644 (file)
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kex.h,v 1.29 2002/02/14 23:41:01 markus Exp $ */
+/*     $OpenBSD: kex.h,v 1.30 2002/03/18 17:50:31 provos Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -111,6 +111,7 @@ struct Kex {
        char    *server_version_string;
        int     (*verify_host_key)(Key *);
        Key     *(*load_host_key)(int);
+       int     (*host_key_index)(Key *);
 };
 
 Kex    *kex_setup(char *[PROPOSAL_MAX]);
diff --git a/kexdh.c b/kexdh.c
index eaf497ca7f1d8ff20628fddca017a58a5c160e47..1e91e2550228134df0a7567149a8a4119e870f4e 100644 (file)
--- a/kexdh.c
+++ b/kexdh.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $");
+RCSID("$OpenBSD: kexdh.c,v 1.18 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/crypto.h>
 #include <openssl/bn.h>
@@ -37,6 +37,7 @@ RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $");
 #include "packet.h"
 #include "dh.h"
 #include "ssh2.h"
+#include "monitor_wrap.h"
 
 static u_char *
 kex_dh_hash(
@@ -275,7 +276,7 @@ kexdh_server(Kex *kex)
 
        /* sign H */
        /* XXX hashlen depends on KEX */
-       key_sign(server_host_key, &signature, &slen, hash, 20);
+       PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
 
        /* destroy_sensitive_data(); */
 
index 61896e6ed467685a995c175aa016b7cc051d7b8f..7379e8d103ec9fe28f977244a142047594fd8b00 100644 (file)
--- a/kexgex.c
+++ b/kexgex.c
@@ -24,7 +24,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $");
+RCSID("$OpenBSD: kexgex.c,v 1.21 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/bn.h>
 
@@ -38,6 +38,7 @@ RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $");
 #include "dh.h"
 #include "ssh2.h"
 #include "compat.h"
+#include "monitor_wrap.h"
 
 static u_char *
 kexgex_hash(
@@ -296,7 +297,8 @@ kexgex_server(Kex *kex)
                fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
                    min, nbits, max);
 
-       dh = choose_dh(min, nbits, max);
+       /* Contact privileged parent */
+       dh = PRIVSEP(choose_dh(min, nbits, max));
        if (dh == NULL)
                packet_disconnect("Protocol error: no matching DH grp found");
 
@@ -379,7 +381,7 @@ kexgex_server(Kex *kex)
 
        /* sign H */
        /* XXX hashlen depends on KEX */
-       key_sign(server_host_key, &signature, &slen, hash, 20);
+       PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
 
        /* destroy_sensitive_data(); */
 
@@ -390,6 +392,7 @@ kexgex_server(Kex *kex)
        packet_put_bignum2(dh->pub_key);        /* f */
        packet_put_string(signature, slen);
        packet_send();
+
        xfree(signature);
        xfree(server_host_key_blob);
        /* have keys, free DH */
diff --git a/monitor.c b/monitor.c
new file mode 100644 (file)
index 0000000..921ad98
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,1440 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2002 Markus Friedl <markus@openbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: monitor.c,v 1.6 2002/03/21 18:38:33 stevesk Exp $");
+
+#include <openssl/dh.h>
+
+#ifdef SKEY
+#include <skey.h>
+#endif
+
+#include "ssh.h"
+#include "auth.h"
+#include "kex.h"
+#include "dh.h"
+#include "zlib.h"
+#include "packet.h"
+#include "auth-options.h"
+#include "sshpty.h"
+#include "channels.h"
+#include "session.h"
+#include "sshlogin.h"
+#include "canohost.h"
+#include "log.h"
+#include "servconf.h"
+#include "monitor.h"
+#include "monitor_mm.h"
+#include "monitor_wrap.h"
+#include "monitor_fdpass.h"
+#include "xmalloc.h"
+#include "misc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "compat.h"
+#include "ssh2.h"
+#include "mpaux.h"
+
+/* Imports */
+extern ServerOptions options;
+extern u_int utmp_len;
+extern Newkeys *current_keys[];
+extern z_stream incoming_stream;
+extern z_stream outgoing_stream;
+extern u_char session_id[];
+extern Buffer input, output;
+extern Buffer auth_debug;
+extern int auth_debug_init;
+
+/* State exported from the child */
+
+struct {
+       z_stream incoming;
+       z_stream outgoing;
+       u_char *keyin;
+       u_int keyinlen;
+       u_char *keyout;
+       u_int keyoutlen;
+       u_char *ivin;
+       u_int ivinlen;
+       u_char *ivout;
+       u_int ivoutlen;
+       int ssh1cipher;
+       int ssh1protoflags;
+       u_char *input;
+       u_int ilen;
+       u_char *output;
+       u_int olen;
+} child_state;
+
+/* Functions on the montior that answer unprivileged requests */
+
+int mm_answer_moduli(int, Buffer *);
+int mm_answer_sign(int, Buffer *);
+int mm_answer_pwnamallow(int, Buffer *);
+int mm_answer_authserv(int, Buffer *);
+int mm_answer_authpassword(int, Buffer *);
+int mm_answer_bsdauthquery(int, Buffer *);
+int mm_answer_bsdauthrespond(int, Buffer *);
+int mm_answer_skeyquery(int, Buffer *);
+int mm_answer_skeyrespond(int, Buffer *);
+int mm_answer_keyallowed(int, Buffer *);
+int mm_answer_keyverify(int, Buffer *);
+int mm_answer_pty(int, Buffer *);
+int mm_answer_pty_cleanup(int, Buffer *);
+int mm_answer_term(int, Buffer *);
+int mm_answer_rsa_keyallowed(int, Buffer *);
+int mm_answer_rsa_challenge(int, Buffer *);
+int mm_answer_rsa_response(int, Buffer *);
+int mm_answer_sesskey(int, Buffer *);
+int mm_answer_sessid(int, Buffer *);
+
+static Authctxt *authctxt;
+static BIGNUM *ssh1_challenge = NULL;  /* used for ssh1 rsa auth */
+
+/* local state for key verify */
+static u_char *key_blob = NULL;
+static u_int key_bloblen = 0;
+static int key_blobtype = MM_NOKEY;
+static u_char *hostbased_cuser = NULL;
+static u_char *hostbased_chost = NULL;
+static char *auth_method = "unknown";
+
+struct mon_table {
+       enum monitor_reqtype type;
+       int flags;
+       int (*f)(int, Buffer *);
+};
+
+#define MON_ISAUTH     0x0004  /* Required for Authentication */
+#define MON_AUTHDECIDE 0x0008  /* Decides Authentication */
+#define MON_ONCE       0x0010  /* Disable after calling */
+
+#define MON_AUTH       (MON_ISAUTH|MON_AUTHDECIDE)
+
+#define MON_PERMIT     0x1000  /* Request is permitted */
+
+struct mon_table mon_dispatch_proto20[] = {
+    {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
+    {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+    {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
+    {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+#ifdef BSD_AUTH
+    {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+    {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},
+#endif
+#ifdef SKEY
+    {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
+    {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+#endif
+    {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
+    {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_postauth20[] = {
+    {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
+    {MONITOR_REQ_SIGN, 0, mm_answer_sign},
+    {MONITOR_REQ_PTY, 0, mm_answer_pty},
+    {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
+    {MONITOR_REQ_TERM, 0, mm_answer_term},
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_proto15[] = {
+    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+    {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey},
+    {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid},
+    {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+    {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH, mm_answer_rsa_keyallowed},
+    {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
+    {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge},
+    {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response},
+#ifdef BSD_AUTH
+    {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+    {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},
+#endif
+#ifdef SKEY
+    {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
+    {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+#endif
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_postauth15[] = {
+    {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
+    {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
+    {MONITOR_REQ_TERM, 0, mm_answer_term},
+    {0, 0, NULL}
+};
+
+struct mon_table *mon_dispatch;
+
+/* Specifies if a certain message is allowed at the moment */
+
+static void
+monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit)
+{
+       while (ent->f != NULL) {
+               if (ent->type == type) {
+                       ent->flags &= ~MON_PERMIT;
+                       ent->flags |= permit ? MON_PERMIT : 0;
+                       return;
+               }
+               ent++;
+       }
+}
+
+static void
+monitor_permit_authentications(int permit)
+{
+       struct mon_table *ent = mon_dispatch;
+
+       while (ent->f != NULL) {
+               if (ent->flags & MON_AUTH) {
+                       ent->flags &= ~MON_PERMIT;
+                       ent->flags |= permit ? MON_PERMIT : 0;
+               }
+               ent++;
+       }
+}
+
+Authctxt *
+monitor_child_preauth(struct monitor *monitor)
+{
+       struct mon_table *ent;
+       int authenticated = 0;
+
+       debug3("preauth child monitor started");
+
+       if (compat20) {
+               mon_dispatch = mon_dispatch_proto20;
+
+               /* Permit requests for moduli and signatures */
+               monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+       } else {
+               mon_dispatch = mon_dispatch_proto15;
+
+               monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
+       }
+
+       authctxt = authctxt_new();
+
+       /* The first few requests do not require asynchronous access */
+       while (!authenticated) {
+               authenticated = monitor_read(monitor, mon_dispatch, &ent);
+               if (authenticated) {
+                       if (!(ent->flags & MON_AUTHDECIDE))
+                               fatal("%s: unexpected authentication from %d",
+                                   __FUNCTION__, ent->type);
+                       if (authctxt->pw->pw_uid == 0 &&
+                           !auth_root_allowed(auth_method))
+                               authenticated = 0;
+               }
+
+               if (ent->flags & MON_AUTHDECIDE) {
+                       auth_log(authctxt, authenticated, auth_method,
+                           compat20 ? " ssh2" : "");
+                       if (!authenticated)
+                               authctxt->failures++;
+               }
+       }
+
+       if (!authctxt->valid)
+               fatal("%s: authenticated invalid user", __FUNCTION__);
+
+       debug("%s: %s has been authenticated by privileged process",
+           __FUNCTION__, authctxt->user);
+
+       mm_get_keystate(monitor);
+
+       return (authctxt);
+}
+
+void
+monitor_child_postauth(struct monitor *monitor)
+{
+       if (compat20) {
+               mon_dispatch = mon_dispatch_postauth20;
+
+               /* Permit requests for moduli and signatures */
+               monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+
+       } else {
+               mon_dispatch = mon_dispatch_postauth15;
+               monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+       }
+       if (!no_pty_flag) {
+               monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
+       }
+
+       for (;;)
+               monitor_read(monitor, mon_dispatch, NULL);
+}
+
+void
+monitor_sync(struct monitor *monitor)
+{
+       /* The member allocation is not visible, so sync it */
+       mm_share_sync(&monitor->m_zlib, &monitor->m_zback);
+}
+
+int
+monitor_read(struct monitor *monitor, struct mon_table *ent,
+    struct mon_table **pent)
+{
+       Buffer m;
+       int ret;
+       u_char type;
+
+       buffer_init(&m);
+
+       mm_request_receive(monitor->m_sendfd, &m);
+       type = buffer_get_char(&m);
+
+       debug3("%s: checking request %d", __FUNCTION__, type);
+
+       while (ent->f != NULL) {
+               if (ent->type == type)
+                       break;
+               ent++;
+       }
+
+       if (ent->f != NULL) {
+               if (!(ent->flags & MON_PERMIT))
+                       fatal("%s: unpermitted request %d", __FUNCTION__,
+                           type);
+               ret = (*ent->f)(monitor->m_sendfd, &m);
+               buffer_free(&m);
+
+               /* The child may use this request only once, disable it */
+               if (ent->flags & MON_ONCE) {
+                       debug2("%s: %d used once, disabling now", __FUNCTION__,
+                           type);
+                       ent->flags &= ~MON_PERMIT;
+               }
+
+               if (pent != NULL)
+                       *pent = ent;
+
+               return ret;
+       }
+
+       fatal("%s: unsupported request: %d\n", __FUNCTION__, type);
+
+       /* NOTREACHED */
+       return (-1);
+}
+
+/* allowed key state */
+static int
+monitor_allowed_key(u_char *blob, u_int bloblen)
+{
+       /* make sure key is allowed */
+       if (key_blob == NULL || key_bloblen != bloblen ||
+           memcmp(key_blob, blob, key_bloblen))
+               return (0);
+       return (1);
+}
+
+static void
+monitor_reset_key_state(void)
+{
+       /* reset state */
+       if (key_blob != NULL)
+               xfree(key_blob);
+       if (hostbased_cuser != NULL)
+               xfree(hostbased_cuser);
+       if (hostbased_chost != NULL)
+               xfree(hostbased_chost);
+       key_blob = NULL;
+       key_bloblen = 0;
+       key_blobtype = MM_NOKEY;
+       hostbased_cuser = NULL;
+       hostbased_chost = NULL;
+}
+
+int
+mm_answer_moduli(int socket, Buffer *m)
+{
+       DH *dh;
+       int min, want, max;
+
+       min = buffer_get_int(m);
+       want = buffer_get_int(m);
+       max = buffer_get_int(m);
+
+       debug3("%s: got parameters: %d %d %d",
+           __FUNCTION__, min, want, max);
+       /* We need to check here, too, in case the child got corrupted */
+       if (max < min || want < min || max < want)
+               fatal("%s: bad parameters: %d %d %d",
+                   __FUNCTION__, min, want, max);
+
+       buffer_clear(m);
+
+       dh = choose_dh(min, want, max);
+       if (dh == NULL) {
+               buffer_put_char(m, 0);
+               return (0);
+       } else {
+               /* Send first bignum */
+               buffer_put_char(m, 1);
+               buffer_put_bignum2(m, dh->p);
+               buffer_put_bignum2(m, dh->g);
+
+               DH_free(dh);
+       }
+       mm_request_send(socket, MONITOR_ANS_MODULI, m);
+       return (0);
+}
+
+int
+mm_answer_sign(int socket, Buffer *m)
+{
+       Key *key;
+       u_char *p;
+       u_char *signature;
+       u_int siglen, datlen;
+       int keyid;
+
+       debug3("%s", __FUNCTION__);
+
+       keyid = buffer_get_int(m);
+       p = buffer_get_string(m, &datlen);
+
+       if (datlen != 20)
+               fatal("%s: data length incorrect: %d", __FUNCTION__, datlen);
+
+       if ((key = get_hostkey_by_index(keyid)) == NULL)
+               fatal("%s: no hostkey from index %d", __FUNCTION__, keyid);
+       if (key_sign(key, &signature, &siglen, p, datlen) < 0)
+               fatal("%s: key_sign failed", __FUNCTION__);
+
+       debug3("%s: signature %p(%d)", __FUNCTION__, signature, siglen);
+
+       buffer_clear(m);
+       buffer_put_string(m, signature, siglen);
+
+       xfree(p);
+       xfree(signature);
+
+       mm_request_send(socket, MONITOR_ANS_SIGN, m);
+
+       /* Turn on permissions for getpwnam */
+       monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+       return (0);
+}
+
+/* Retrieves the password entry and also checks if the user is permitted */
+
+int
+mm_answer_pwnamallow(int socket, Buffer *m)
+{
+       char *login;
+       struct passwd *pwent;
+       int allowed = 0;
+
+       debug3("%s", __FUNCTION__);
+
+       if (authctxt->attempt++ != 0)
+               fatal("%s: multiple attempts for getpwnam", __FUNCTION__);
+
+       login = buffer_get_string(m, NULL);
+
+       pwent = getpwnamallow(login);
+
+       authctxt->user = xstrdup(login);
+       setproctitle("%s [priv]", pwent ? login : "unknown");
+       xfree(login);
+
+       buffer_clear(m);
+
+       if (pwent == NULL) {
+               buffer_put_char(m, 0);
+               goto out;
+       }
+
+       allowed = 1;
+       authctxt->pw = pwent;
+       authctxt->valid = 1;
+
+       buffer_put_char(m, 1);
+       buffer_put_string(m, pwent, sizeof(struct passwd));
+       buffer_put_cstring(m, pwent->pw_name);
+       buffer_put_cstring(m, "*");
+       buffer_put_cstring(m, pwent->pw_gecos);
+       buffer_put_cstring(m, pwent->pw_class);
+       buffer_put_cstring(m, pwent->pw_dir);
+       buffer_put_cstring(m, pwent->pw_shell);
+
+ out:
+       debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, allowed);
+       mm_request_send(socket, MONITOR_ANS_PWNAM, m);
+
+       /* For SSHv1 allow authentication now */
+       if (!compat20)
+               monitor_permit_authentications(1);
+       else
+               /* Allow service/style information on the auth context */
+               monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
+
+
+       return (0);
+}
+
+int
+mm_answer_authserv(int socket, Buffer *m)
+{
+       monitor_permit_authentications(1);
+
+       authctxt->service = buffer_get_string(m, NULL);
+       authctxt->style = buffer_get_string(m, NULL);
+       debug3("%s: service=%s, style=%s",
+           __FUNCTION__, authctxt->service, authctxt->style);
+
+       if (strlen(authctxt->style) == 0) {
+               xfree(authctxt->style);
+               authctxt->style = NULL;
+       }
+
+       return (0);
+}
+
+int
+mm_answer_authpassword(int socket, Buffer *m)
+{
+       static int call_count;
+       char *passwd;
+       int authenticated, plen;
+
+       passwd = buffer_get_string(m, &plen);
+       /* Only authenticate if the context is valid */
+       authenticated = authctxt->valid && auth_password(authctxt, passwd);
+       memset(passwd, 0, strlen(passwd));
+       xfree(passwd);
+
+       buffer_clear(m);
+       buffer_put_int(m, authenticated);
+
+       debug3("%s: sending result %d", __FUNCTION__, authenticated);
+       mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m);
+
+       call_count++;
+       if (plen == 0 && call_count == 1)
+               auth_method = "none";
+       else
+               auth_method = "password";
+
+       /* Causes monitor loop to terminate if authenticated */
+       return (authenticated);
+}
+
+#ifdef BSD_AUTH
+int
+mm_answer_bsdauthquery(int socket, Buffer *m)
+{
+       char *name, *infotxt;
+       u_int numprompts;
+       u_int *echo_on;
+       char **prompts;
+       int res;
+
+       res = bsdauth_query(authctxt, &name, &infotxt, &numprompts,
+           &prompts, &echo_on);
+
+       buffer_clear(m);
+       buffer_put_int(m, res);
+       if (res != -1)
+               buffer_put_cstring(m, prompts[0]);
+
+       debug3("%s: sending challenge res: %d", __FUNCTION__, res);
+       mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m);
+
+       if (res != -1) {
+               xfree(name);
+               xfree(infotxt);
+               xfree(prompts);
+               xfree(echo_on);
+       }
+
+       return (0);
+}
+
+int
+mm_answer_bsdauthrespond(int socket, Buffer *m)
+{
+       char *response;
+       int authok;
+
+       if (authctxt->as == 0)
+               fatal("%s: no bsd auth session", __FUNCTION__);
+
+       response = buffer_get_string(m, NULL);
+       authok = auth_userresponse(authctxt->as, response, 0);
+       authctxt->as = NULL;
+       debug3("%s: <%s> = <%d>", __FUNCTION__, response, authok);
+       xfree(response);
+
+       buffer_clear(m);
+       buffer_put_int(m, authok);
+
+       debug3("%s: sending authenticated: %d", __FUNCTION__, authok);
+       mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m);
+
+       auth_method = "bsdauth";
+
+       return (authok != 0);
+}
+#endif
+
+#ifdef SKEY
+int
+mm_answer_skeyquery(int socket, Buffer *m)
+{
+       struct skey skey;
+       char challenge[1024];
+       int res;
+
+       res = skeychallenge(&skey, authctxt->user, challenge);
+
+       buffer_clear(m);
+       buffer_put_int(m, res);
+       if (res != -1)
+               buffer_put_cstring(m, challenge);
+
+       debug3("%s: sending challenge res: %d", __FUNCTION__, res);
+       mm_request_send(socket, MONITOR_ANS_SKEYQUERY, m);
+
+       return (0);
+}
+
+int
+mm_answer_skeyrespond(int socket, Buffer *m)
+{
+       char *response;
+       int authok;
+
+       response = buffer_get_string(m, NULL);
+
+       authok = (authctxt->valid &&
+           skey_haskey(authctxt->pw->pw_name) == 0 &&
+           skey_passcheck(authctxt->pw->pw_name, response) != -1);
+
+       xfree(response);
+
+       buffer_clear(m);
+       buffer_put_int(m, authok);
+
+       debug3("%s: sending authenticated: %d", __FUNCTION__, authok);
+       mm_request_send(socket, MONITOR_ANS_SKEYRESPOND, m);
+
+       auth_method = "skey";
+
+       return (authok != 0);
+}
+#endif
+
+static void
+mm_append_debug(Buffer *m)
+{
+       if (auth_debug_init && buffer_len(&auth_debug)) {
+               debug3("%s: Appending debug messages for child", __FUNCTION__);
+               buffer_append(m, buffer_ptr(&auth_debug),
+                   buffer_len(&auth_debug));
+               buffer_clear(&auth_debug);
+       }
+}
+
+int
+mm_answer_keyallowed(int socket, Buffer *m)
+{
+       Key *key;
+       u_char *cuser, *chost, *blob;
+       u_int bloblen;
+       enum mm_keytype type = 0;
+       int allowed = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       type = buffer_get_int(m);
+       cuser = buffer_get_string(m, NULL);
+       chost = buffer_get_string(m, NULL);
+       blob = buffer_get_string(m, &bloblen);
+
+       key = key_from_blob(blob, bloblen);
+
+       if ((compat20 && type == MM_RSAHOSTKEY) ||
+           (!compat20 && type != MM_RSAHOSTKEY))
+               fatal("%s: key type and protocol mismatch", __FUNCTION__);
+
+       debug3("%s: key_from_blob: %p", __FUNCTION__, key);
+
+       if (key != NULL && authctxt->pw != NULL) {
+               switch(type) {
+               case MM_USERKEY:
+                       allowed = user_key_allowed(authctxt->pw, key);
+                       break;
+               case MM_HOSTKEY:
+                       allowed = hostbased_key_allowed(authctxt->pw,
+                           cuser, chost, key);
+                       break;
+               case MM_RSAHOSTKEY:
+                       key->type = KEY_RSA1; /* XXX */
+                       allowed = auth_rhosts_rsa_key_allowed(authctxt->pw,
+                           cuser, chost, key);
+                       break;
+               default:
+                       fatal("%s: unknown key type %d", __FUNCTION__, type);
+                       break;
+               }
+               key_free(key);
+       }
+
+       /* clear temporarily storage (used by verify) */
+       monitor_reset_key_state();
+
+       if (allowed) {
+               /* Save temporarily for comparison in verify */
+               key_blob = blob;
+               key_bloblen = bloblen;
+               key_blobtype = type;
+               hostbased_cuser = cuser;
+               hostbased_chost = chost;
+       }
+
+       debug3("%s: key %p is %s",
+           __FUNCTION__, key, allowed ? "allowed" : "disallowed");
+
+       buffer_clear(m);
+       buffer_put_int(m, allowed);
+
+       mm_append_debug(m);
+
+       mm_request_send(socket, MONITOR_ANS_KEYALLOWED, m);
+
+       if (type == MM_RSAHOSTKEY)
+               monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed);
+
+       return (0);
+}
+
+static int
+monitor_valid_userblob(u_char *data, u_int datalen)
+{
+       Buffer b;
+       u_char *p;
+       u_int len;
+       int fail = 0;
+       int session_id2_len = 20 /*XXX should get from [net] */;
+
+       buffer_init(&b);
+       buffer_append(&b, data, datalen);
+
+       if (datafellows & SSH_OLD_SESSIONID) {
+               buffer_consume(&b, session_id2_len);
+       } else {
+               xfree(buffer_get_string(&b, &len));
+               if (len != session_id2_len)
+                       fail++;
+       }
+       if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+               fail++;
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(authctxt->user, p) != 0) {
+               log("wrong user name passed to monitor: expected %s != %.100s",
+                   authctxt->user, p);
+               fail++;
+       }
+       xfree(p);
+       buffer_skip_string(&b);
+       if (datafellows & SSH_BUG_PKAUTH) {
+               if (!buffer_get_char(&b))
+                       fail++;
+       } else {
+               p = buffer_get_string(&b, NULL);
+               if (strcmp("publickey", p) != 0)
+                       fail++;
+               xfree(p);
+               if (!buffer_get_char(&b))
+                       fail++;
+               buffer_skip_string(&b);
+       }
+       buffer_skip_string(&b);
+       if (buffer_len(&b) != 0)
+               fail++;
+       buffer_free(&b);
+       return (fail == 0);
+}
+
+static int
+monitor_valid_hostbasedblob(u_char *data, u_int datalen, u_char *cuser,
+    u_char *chost)
+{
+       Buffer b;
+       u_char *p;
+       u_int len;
+       int fail = 0;
+       int session_id2_len = 20 /*XXX should get from [net] */;
+
+       buffer_init(&b);
+       buffer_append(&b, data, datalen);
+
+       xfree(buffer_get_string(&b, &len));
+       if (len != session_id2_len)
+               fail++;
+       if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+               fail++;
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(authctxt->user, p) != 0) {
+               log("wrong user name passed to monitor: expected %s != %.100s",
+                   authctxt->user, p);
+               fail++;
+       }
+       xfree(p);
+       buffer_skip_string(&b); /* service */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(p, "hostbased") != 0)
+               fail++;
+       xfree(p);
+       buffer_skip_string(&b); /* pkalg */
+       buffer_skip_string(&b); /* pkblob */
+
+       /* verify client host, strip trailing dot if necessary */
+       p = buffer_get_string(&b, NULL);
+       if (((len = strlen(p)) > 0) && p[len - 1] == '.')
+               p[len - 1] = '\0';
+       if (strcmp(p, chost) != 0)
+               fail++;
+       xfree(p);
+
+       /* verify client user */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(p, cuser) != 0)
+               fail++;
+       xfree(p);
+
+       if (buffer_len(&b) != 0)
+               fail++;
+       buffer_free(&b);
+       return (fail == 0);
+}
+
+int
+mm_answer_keyverify(int socket, Buffer *m)
+{
+       Key *key;
+       u_char *signature, *data, *blob;
+       u_int signaturelen, datalen, bloblen;
+       int verified = 0;
+       int valid_data = 0;
+
+       blob = buffer_get_string(m, &bloblen);
+       signature = buffer_get_string(m, &signaturelen);
+       data = buffer_get_string(m, &datalen);
+
+       if (hostbased_cuser == NULL || hostbased_chost == NULL ||
+          monitor_allowed_key(blob, bloblen) == NULL)
+               fatal("%s: bad key, not previously allowed", __FUNCTION__);
+
+       key = key_from_blob(blob, bloblen);
+       if (key == NULL)
+               fatal("%s: bad public key blob", __FUNCTION__);
+
+       switch (key_blobtype) {
+       case MM_USERKEY:
+               valid_data = monitor_valid_userblob(data, datalen);
+               break;
+       case MM_HOSTKEY:
+               valid_data = monitor_valid_hostbasedblob(data, datalen,
+                   hostbased_cuser, hostbased_chost);
+               break;
+       default:
+               valid_data = 0;
+               break;
+       }
+       if (!valid_data)
+               fatal("%s: bad signature data blob", __FUNCTION__);
+
+       verified = key_verify(key, signature, signaturelen, data, datalen);
+       debug3("%s: key %p signature %s",
+           __FUNCTION__, key, verified ? "verified" : "unverified");
+
+       key_free(key);
+       xfree(blob);
+       xfree(signature);
+       xfree(data);
+
+       monitor_reset_key_state();
+
+       buffer_clear(m);
+       buffer_put_int(m, verified);
+       mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m);
+
+       auth_method = "publickey";
+
+       return (verified);
+}
+
+static void
+mm_record_login(Session *s, struct passwd *pw)
+{
+       socklen_t fromlen;
+       struct sockaddr_storage from;
+
+       /*
+        * Get IP address of client. If the connection is not a socket, let
+        * the address be 0.0.0.0.
+        */
+       memset(&from, 0, sizeof(from));
+       if (packet_connection_is_on_socket()) {
+               fromlen = sizeof(from);
+               if (getpeername(packet_get_connection_in(),
+                       (struct sockaddr *) & from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       fatal_cleanup();
+               }
+       }
+       /* Record that there was a login on that tty from the remote host. */
+       record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid,
+           get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping),
+           (struct sockaddr *)&from);
+}
+
+static void
+mm_session_close(Session *s)
+{
+       debug3("%s: session %d pid %d", __FUNCTION__, s->self, s->pid);
+       if (s->ttyfd != -1) {
+               debug3("%s: tty %s ptyfd %d",  __FUNCTION__, s->tty, s->ptyfd);
+               fatal_remove_cleanup(session_pty_cleanup2, (void *)s);
+               session_pty_cleanup2(s);
+       }
+       s->used = 0;
+}
+
+int
+mm_answer_pty(int socket, Buffer *m)
+{
+       extern struct monitor *monitor;
+       Session *s;
+       int res, fd0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_clear(m);
+       s = session_new();
+       if (s == NULL)
+               goto error;
+       s->authctxt = authctxt;
+       s->pw = authctxt->pw;
+       s->pid = monitor->m_pid;
+       res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
+       if (res == 0)
+               goto error;
+       fatal_add_cleanup(session_pty_cleanup2, (void *)s);
+       pty_setowner(authctxt->pw, s->tty);
+
+       buffer_put_int(m, 1);
+       buffer_put_cstring(m, s->tty);
+       mm_request_send(socket, MONITOR_ANS_PTY, m);
+
+       mm_send_fd(socket, s->ptyfd);
+       mm_send_fd(socket, s->ttyfd);
+
+       /* We need to trick ttyslot */
+       if (dup2(s->ttyfd, 0) == -1)
+               fatal("%s: dup2", __FUNCTION__);
+
+       mm_record_login(s, authctxt->pw);
+
+       /* Now we can close the file descriptor again */
+       close(0);
+
+       /* make sure nothing uses fd 0 */
+       if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+               fatal("%s: open(/dev/null): %s", __FUNCTION__, strerror(errno));
+       if (fd0 != 0)
+               error("%s: fd0 %d != 0", __FUNCTION__, fd0);
+
+       /* slave is not needed */
+       close(s->ttyfd);
+       s->ttyfd = s->ptyfd;
+       /* no need to dup() because nobody closes ptyfd */
+       s->ptymaster = s->ptyfd;
+
+       debug3("%s: tty %s ptyfd %d",  __FUNCTION__, s->tty, s->ttyfd);
+
+       return (0);
+
+ error:
+       if (s != NULL)
+               mm_session_close(s);
+       buffer_put_int(m, 0);
+       mm_request_send(socket, MONITOR_ANS_PTY, m);
+       return (0);
+}
+
+int
+mm_answer_pty_cleanup(int socket, Buffer *m)
+{
+       Session *s;
+       char *tty;
+
+       debug3("%s entering", __FUNCTION__);
+
+       tty = buffer_get_string(m, NULL);
+       if ((s = session_by_tty(tty)) != NULL)
+               mm_session_close(s);
+       buffer_clear(m);
+       xfree(tty);
+       return (0);
+}
+
+int
+mm_answer_sesskey(int socket, Buffer *m)
+{
+       BIGNUM *p;
+       int rsafail;
+
+       /* Turn off permissions */
+       monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
+
+       if ((p = BN_new()) == NULL)
+               fatal("%s: BN_new", __FUNCTION__);
+
+       buffer_get_bignum2(m, p);
+
+       rsafail = ssh1_session_key(p);
+
+       buffer_clear(m);
+       buffer_put_int(m, rsafail);
+       buffer_put_bignum2(m, p);
+
+       BN_clear_free(p);
+
+       mm_request_send(socket, MONITOR_ANS_SESSKEY, m);
+
+       /* Turn on permissions for sessid passing */
+       monitor_permit(mon_dispatch, MONITOR_REQ_SESSID, 1);
+
+       return (0);
+}
+
+int
+mm_answer_sessid(int socket, Buffer *m)
+{
+       int i;
+
+       debug3("%s entering", __FUNCTION__);
+
+       if (buffer_len(m) != 16)
+               fatal("%s: bad ssh1 session id", __FUNCTION__);
+       for (i = 0; i < 16; i++)
+               session_id[i] = buffer_get_char(m);
+
+       /* Turn on permissions for getpwnam */
+       monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+       return (0);
+}
+
+int
+mm_answer_rsa_keyallowed(int socket, Buffer *m)
+{
+       BIGNUM *client_n;
+       Key *key = NULL;
+       u_char *blob = NULL;
+       u_int blen = 0;
+       int allowed = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       if (authctxt->valid) {
+               if ((client_n = BN_new()) == NULL)
+                       fatal("%s: BN_new", __FUNCTION__);
+               buffer_get_bignum2(m, client_n);
+               allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key);
+               BN_clear_free(client_n);
+       }
+       buffer_clear(m);
+       buffer_put_int(m, allowed);
+
+       /* clear temporarily storage (used by generate challenge) */
+       monitor_reset_key_state();
+
+       if (allowed && key != NULL) {
+               key->type = KEY_RSA;    /* cheat for key_to_blob */
+               if (key_to_blob(key, &blob, &blen) == 0)
+                       fatal("%s: key_to_blob failed", __FUNCTION__);
+               buffer_put_string(m, blob, blen);
+
+               /* Save temporarily for comparison in verify */
+               key_blob = blob;
+               key_bloblen = blen;
+               key_blobtype = MM_RSAUSERKEY;
+               key_free(key);
+       }
+
+       mm_append_debug(m);
+
+       mm_request_send(socket, MONITOR_ANS_RSAKEYALLOWED, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed);
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0);
+       return (0);
+}
+
+int
+mm_answer_rsa_challenge(int socket, Buffer *m)
+{
+       Key *key = NULL;
+       u_char *blob;
+       u_int blen;
+
+       debug3("%s entering", __FUNCTION__);
+
+       if (!authctxt->valid)
+               fatal("%s: authctxt not valid", __FUNCTION__);
+       blob = buffer_get_string(m, &blen);
+       if (!monitor_allowed_key(blob, blen))
+               fatal("%s: bad key, not previously allowed", __FUNCTION__);
+       if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY)
+               fatal("%s: key type mismatch", __FUNCTION__);
+       if ((key = key_from_blob(blob, blen)) == NULL)
+               fatal("%s: received bad key", __FUNCTION__);
+
+       if (ssh1_challenge)
+               BN_clear_free(ssh1_challenge);
+       ssh1_challenge = auth_rsa_generate_challenge(key);
+
+       buffer_clear(m);
+       buffer_put_bignum2(m, ssh1_challenge);
+
+       debug3("%s sending reply", __FUNCTION__);
+       mm_request_send(socket, MONITOR_ANS_RSACHALLENGE, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1);
+       return (0);
+}
+
+int
+mm_answer_rsa_response(int socket, Buffer *m)
+{
+       Key *key = NULL;
+       u_char *blob, *response;
+       u_int blen, len;
+       int success;
+
+       debug3("%s entering", __FUNCTION__);
+
+       if (!authctxt->valid)
+               fatal("%s: authctxt not valid", __FUNCTION__);
+       if (ssh1_challenge == NULL)
+               fatal("%s: no ssh1_challenge", __FUNCTION__);
+
+       blob = buffer_get_string(m, &blen);
+       if (!monitor_allowed_key(blob, blen))
+               fatal("%s: bad key, not previously allowed", __FUNCTION__);
+       if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY)
+               fatal("%s: key type mismatch: %d", __FUNCTION__, key_blobtype);
+       if ((key = key_from_blob(blob, blen)) == NULL)
+               fatal("%s: received bad key", __FUNCTION__);
+       response = buffer_get_string(m, &len);
+       if (len != 16)
+               fatal("%s: received bad response to challenge", __FUNCTION__);
+       success = auth_rsa_verify_response(key, ssh1_challenge, response);
+
+       key_free(key);
+       xfree(response);
+
+       auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa";
+
+       /* reset state */
+       BN_clear_free(ssh1_challenge);
+       ssh1_challenge = NULL;
+       monitor_reset_key_state();
+
+       buffer_clear(m);
+       buffer_put_int(m, success);
+       mm_request_send(socket, MONITOR_ANS_RSARESPONSE, m);
+
+       return (success);
+}
+
+int
+mm_answer_term(int socket, Buffer *req)
+{
+       extern struct monitor *monitor;
+       int res, status;
+
+       debug3("%s: tearing down sessions", __FUNCTION__);
+
+       /* The child is terminating */
+       session_destroy_all(&mm_session_close);
+
+       if (waitpid(monitor->m_pid, &status, 0) == -1)
+               exit(1);
+
+       res = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
+
+       /* Terminate process */
+       exit (res);
+}
+
+void
+monitor_apply_keystate(struct monitor *monitor)
+{
+       if (compat20) {
+               set_newkeys(MODE_IN);
+               set_newkeys(MODE_OUT);
+       } else {
+               u_char key[SSH_SESSION_KEY_LENGTH];
+
+               memset(key, 'a', sizeof(key));
+               packet_set_protocol_flags(child_state.ssh1protoflags);
+               packet_set_encryption_key(key, SSH_SESSION_KEY_LENGTH,
+                   child_state.ssh1cipher);
+       }
+
+       packet_set_keycontext(MODE_OUT, child_state.keyout);
+       xfree(child_state.keyout);
+       packet_set_keycontext(MODE_IN, child_state.keyin);
+       xfree(child_state.keyin);
+
+       if (!compat20) {
+               packet_set_iv(MODE_OUT, child_state.ivout);
+               xfree(child_state.ivout);
+               packet_set_iv(MODE_IN, child_state.ivin);
+               xfree(child_state.ivin);
+       }
+
+       memcpy(&incoming_stream, &child_state.incoming,
+           sizeof(incoming_stream));
+       memcpy(&outgoing_stream, &child_state.outgoing,
+           sizeof(outgoing_stream));
+
+       /* Update with new address */
+       mm_init_compression(monitor->m_zlib);
+
+       /* Network I/O buffers */
+       /* XXX inefficient for large buffers, need: buffer_init_from_string */
+       buffer_clear(&input);
+       buffer_append(&input, child_state.input, child_state.ilen);
+       memset(child_state.input, 0, child_state.ilen);
+       xfree(child_state.input);
+
+       buffer_clear(&output);
+       buffer_append(&output, child_state.output, child_state.olen);
+       memset(child_state.output, 0, child_state.olen);
+       xfree(child_state.output);
+}
+
+static Kex *
+mm_get_kex(Buffer *m)
+{
+       Kex *kex;
+       void *blob;
+       u_int bloblen;
+
+       kex = xmalloc(sizeof(*kex));
+       memset(kex, 0, sizeof(*kex));
+       kex->session_id = buffer_get_string(m, &kex->session_id_len);
+       kex->we_need = buffer_get_int(m);
+       kex->server = 1;
+       kex->hostkey_type = buffer_get_int(m);
+       kex->kex_type = buffer_get_int(m);
+       blob = buffer_get_string(m, &bloblen);
+       buffer_init(&kex->my);
+       buffer_append(&kex->my, blob, bloblen);
+       xfree(blob);
+       blob = buffer_get_string(m, &bloblen);
+       buffer_init(&kex->peer);
+       buffer_append(&kex->peer, blob, bloblen);
+       xfree(blob);
+       kex->done = 1;
+       kex->flags = buffer_get_int(m);
+       kex->client_version_string = buffer_get_string(m, NULL);
+       kex->server_version_string = buffer_get_string(m, NULL);
+       kex->load_host_key=&get_hostkey_by_type;
+       kex->host_key_index=&get_hostkey_index;
+
+       return (kex);
+}
+
+/* This function requries careful sanity checking */
+
+void
+mm_get_keystate(struct monitor *monitor)
+{
+       Buffer m;
+       u_char *blob, *p;
+       u_int bloblen, plen;
+
+       debug3("%s: Waiting for new keys", __FUNCTION__);
+
+       buffer_init(&m);
+       mm_request_receive_expect(monitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m);
+       if (!compat20) {
+               child_state.ssh1protoflags = buffer_get_int(&m);
+               child_state.ssh1cipher = buffer_get_int(&m);
+               child_state.ivout = buffer_get_string(&m,
+                   &child_state.ivoutlen);
+               child_state.ivin = buffer_get_string(&m, &child_state.ivinlen);
+               goto skip;
+       } else {
+               /* Get the Kex for rekeying */
+               *monitor->m_pkex = mm_get_kex(&m);
+       }
+
+       blob = buffer_get_string(&m, &bloblen);
+       current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen);
+       xfree(blob);
+
+       debug3("%s: Waiting for second key", __FUNCTION__);
+       blob = buffer_get_string(&m, &bloblen);
+       current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen);
+       xfree(blob);
+
+       /* Now get sequence numbers for the packets */
+       packet_set_seqnr(MODE_OUT, buffer_get_int(&m));
+       packet_set_seqnr(MODE_IN, buffer_get_int(&m));
+
+ skip:
+       /* Get the key context */
+       child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen);
+       child_state.keyin  = buffer_get_string(&m, &child_state.keyinlen);
+
+       debug3("%s: Getting compression state", __FUNCTION__);
+       /* Get compression state */
+       p = buffer_get_string(&m, &plen);
+       if (plen != sizeof(child_state.outgoing))
+               fatal("%s: bad request size", __FUNCTION__);
+       memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing));
+       xfree(p);
+
+       p = buffer_get_string(&m, &plen);
+       if (plen != sizeof(child_state.incoming))
+               fatal("%s: bad request size", __FUNCTION__);
+       memcpy(&child_state.incoming, p, sizeof(child_state.incoming));
+       xfree(p);
+
+       /* Network I/O buffers */
+       debug3("%s: Getting Network I/O buffers", __FUNCTION__);
+       child_state.input = buffer_get_string(&m, &child_state.ilen);
+       child_state.output = buffer_get_string(&m, &child_state.olen);
+
+       buffer_free(&m);
+}
+
+
+/* Allocation functions for zlib */
+void *
+mm_zalloc(struct mm_master *mm, u_int ncount, u_int size)
+{
+       void *address;
+
+       address = mm_malloc(mm, size * ncount);
+
+       return (address);
+}
+
+void
+mm_zfree(struct mm_master *mm, void *address)
+{
+       mm_free(mm, address);
+}
+
+void
+mm_init_compression(struct mm_master *mm)
+{
+       outgoing_stream.zalloc = (alloc_func)mm_zalloc;
+       outgoing_stream.zfree = (free_func)mm_zfree;
+       outgoing_stream.opaque = mm;
+
+       incoming_stream.zalloc = (alloc_func)mm_zalloc;
+       incoming_stream.zfree = (free_func)mm_zfree;
+       incoming_stream.opaque = mm;
+}
+
+/* XXX */
+
+#define FD_CLOSEONEXEC(x) do { \
+       if (fcntl(x, F_SETFD, 1) == -1) \
+               fatal("fcntl(%d, F_SETFD)", x); \
+} while (0)
+
+static void
+monitor_socketpair(int *pair)
+{
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+               fatal("%s: socketpair", __FUNCTION__);
+       FD_CLOSEONEXEC(pair[0]);
+       FD_CLOSEONEXEC(pair[1]);
+}
+
+#define MM_MEMSIZE     65536
+
+struct monitor *
+monitor_init(void)
+{
+       struct monitor *mon;
+       int pair[2];
+
+       mon = xmalloc(sizeof(*mon));
+
+       monitor_socketpair(pair);
+
+       mon->m_recvfd = pair[0];
+       mon->m_sendfd = pair[1];
+
+       /* Used to share zlib space across processes */
+       mon->m_zback = mm_create(NULL, MM_MEMSIZE);
+       mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE);
+
+       /* Compression needs to share state across borders */
+       mm_init_compression(mon->m_zlib);
+
+       return mon;
+}
+
+void
+monitor_reinit(struct monitor *mon)
+{
+       int pair[2];
+
+       monitor_socketpair(pair);
+
+       mon->m_recvfd = pair[0];
+       mon->m_sendfd = pair[1];
+}
diff --git a/monitor.h b/monitor.h
new file mode 100644 (file)
index 0000000..da7f780
--- /dev/null
+++ b/monitor.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MONITOR_H_
+#define _MONITOR_H_
+
+enum monitor_reqtype {
+       MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
+       MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
+       MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
+       MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
+       MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD,
+       MONITOR_REQ_BSDAUTHQUERY, MONITOR_ANS_BSDAUTHQUERY,
+       MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
+       MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
+       MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+       MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
+       MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
+       MONITOR_REQ_KEYEXPORT,
+       MONITOR_REQ_PTY, MONITOR_ANS_PTY,
+       MONITOR_REQ_PTYCLEANUP,
+       MONITOR_REQ_SESSKEY, MONITOR_ANS_SESSKEY,
+       MONITOR_REQ_SESSID,
+       MONITOR_REQ_RSAKEYALLOWED, MONITOR_ANS_RSAKEYALLOWED,
+       MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE,
+       MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE,
+       MONITOR_REQ_TERM,
+};
+
+struct mm_master;
+struct monitor {
+       int                      m_recvfd;
+       int                      m_sendfd;
+       struct mm_master        *m_zback;
+       struct mm_master        *m_zlib;
+       struct Kex              **m_pkex;
+       int                      m_pid;
+};
+
+struct monitor *monitor_init(void);
+void monitor_reinit(struct monitor *);
+void monitor_sync(struct monitor *);
+
+struct Authctxt;
+struct Authctxt *monitor_child_preauth(struct monitor *);
+void monitor_child_postauth(struct monitor *);
+
+struct mon_table;
+int monitor_read(struct monitor*, struct mon_table *, struct mon_table **);
+
+/* Prototypes for request sending and receiving */
+void mm_request_send(int, enum monitor_reqtype, Buffer *);
+void mm_request_receive(int, Buffer *);
+void mm_request_receive_expect(int, enum monitor_reqtype, Buffer *);
+
+#endif /* _MONITOR_H_ */
diff --git a/monitor_fdpass.c b/monitor_fdpass.c
new file mode 100644 (file)
index 0000000..7785535
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: monitor_fdpass.c,v 1.1 2002/03/18 17:27:22 provos Exp $");
+
+#include <sys/uio.h>
+
+#include "log.h"
+#include "monitor_fdpass.h"
+
+void
+mm_send_fd(int socket, int fd)
+{
+       struct msghdr msg;
+       char tmp[CMSG_SPACE(sizeof(int))];
+       struct cmsghdr *cmsg;
+       struct iovec vec;
+       char ch;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_control = (caddr_t)tmp;
+       msg.msg_controllen = CMSG_LEN(sizeof(int));
+       cmsg = CMSG_FIRSTHDR(&msg);
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+       *(int *)CMSG_DATA(cmsg) = fd;
+
+       vec.iov_base = &ch;
+       vec.iov_len = 1;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+
+       if (sendmsg(socket, &msg, 0) == -1)
+               fatal("%s: sendmsg(%d)", __FUNCTION__, fd);
+}
+
+int
+mm_receive_fd(int socket)
+{
+       struct msghdr msg;
+       char tmp[CMSG_SPACE(sizeof(int))];
+       struct cmsghdr *cmsg;
+       struct iovec vec;
+       char ch;
+
+       memset(&msg, 0, sizeof(msg));
+       vec.iov_base = &ch;
+       vec.iov_len = 1;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+       msg.msg_control = tmp;
+       msg.msg_controllen = sizeof(tmp);
+
+       if (recvmsg(socket, &msg, 0) == -1)
+               fatal("%s: recvmsg", __FUNCTION__);
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (cmsg->cmsg_type != SCM_RIGHTS)
+               fatal("%s: expected type %d got %d", __FUNCTION__,
+                   SCM_RIGHTS, cmsg->cmsg_type);
+       return (*(int *)CMSG_DATA(cmsg));
+}
diff --git a/monitor_fdpass.h b/monitor_fdpass.h
new file mode 100644 (file)
index 0000000..cb6b71c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MM_FDPASS_H_
+#define _MM_FDPASS_H_
+
+void mm_send_fd(int, int);
+int mm_receive_fd(int);
+
+#endif /* _MM_FDPASS_H_ */
diff --git a/monitor_mm.c b/monitor_mm.c
new file mode 100644 (file)
index 0000000..bce98c9
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: monitor_mm.c,v 1.3 2002/03/19 10:41:32 markus Exp $");
+
+#include <sys/mman.h>
+
+#include "ssh.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "monitor_mm.h"
+
+static int
+mm_compare(struct mm_share *a, struct mm_share *b)
+{
+       return ((char *)a->address - (char *)b->address);
+}
+
+RB_GENERATE(mmtree, mm_share, next, mm_compare)
+
+static struct mm_share *
+mm_make_entry(struct mm_master *mm, struct mmtree *head,
+    void *address, size_t size)
+{
+       struct mm_share *tmp, *tmp2;
+
+       if (mm->mmalloc == NULL)
+               tmp = xmalloc(sizeof(struct mm_share));
+       else
+               tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share));
+       tmp->address = address;
+       tmp->size = size;
+
+       tmp2 = RB_INSERT(mmtree, head, tmp);
+       if (tmp2 != NULL)
+               fatal("mm_make_entry(%p): double address %p->%p(%d)",
+                   mm, tmp2, address, size);
+
+       return (tmp);
+}
+
+/* Creates a shared memory area of a certain size */
+
+struct mm_master *
+mm_create(struct mm_master *mmalloc, size_t size)
+{
+       void *address;
+       struct mm_master *mm;
+
+       if (mmalloc == NULL)
+               mm = xmalloc(sizeof(struct mm_master));
+       else
+               mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
+
+       /*
+        * If the memory map has a mm_master it can be completely
+        * shared including authentication between the child
+        * and the client.
+        */
+       mm->mmalloc = mmalloc;
+
+       address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED,
+           -1, 0);
+       if (address == MAP_FAILED)
+               fatal("mmap(%d)", size);
+
+       mm->address = address;
+       mm->size = size;
+
+       RB_INIT(&mm->rb_free);
+       RB_INIT(&mm->rb_allocated);
+
+       mm_make_entry(mm, &mm->rb_free, address, size);
+
+       return (mm);
+}
+
+/* Frees either the allocated or the free list */
+
+static void
+mm_freelist(struct mm_master *mmalloc, struct mmtree *head)
+{
+       struct mm_share *mms, *next;
+
+       for (mms = RB_ROOT(head); mms; mms = next) {
+               next = RB_NEXT(mmtree, head, mms);
+               RB_REMOVE(mmtree, head, mms);
+               if (mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mmalloc, mms);
+       }
+}
+
+/* Destroys a memory mapped area */
+
+void
+mm_destroy(struct mm_master *mm)
+{
+       mm_freelist(mm->mmalloc, &mm->rb_free);
+       mm_freelist(mm->mmalloc, &mm->rb_allocated);
+
+       if (munmap(mm->address, mm->size) == -1)
+               fatal("munmap(%p, %d)", mm->address, mm->size);
+       if (mm->mmalloc == NULL)
+               xfree(mm);
+       else
+               mm_free(mm->mmalloc, mm);
+}
+
+void *
+mm_xmalloc(struct mm_master *mm, size_t size)
+{
+       void *address;
+
+       address = mm_malloc(mm, size);
+       if (address == NULL)
+               fatal("%s: mm_malloc(%d)", __FUNCTION__, size);
+       return (address);
+}
+
+
+/* Allocates data from a memory mapped area */
+
+void *
+mm_malloc(struct mm_master *mm, size_t size)
+{
+       struct mm_share *mms, *tmp;
+
+       if (size == 0)
+               fatal("mm_malloc: try to allocate 0 space");
+
+       size = ((size + MM_MINSIZE - 1) / MM_MINSIZE) * MM_MINSIZE;
+
+       RB_FOREACH(mms, mmtree, &mm->rb_free) {
+               if (mms->size >= size)
+                       break;
+       }
+
+       if (mms == NULL)
+               return (NULL);
+
+       /* Debug */
+       memset(mms->address, 0xd0, size);
+
+       tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size);
+
+       /* Does not change order in RB tree */
+       mms->size -= size;
+       mms->address = (u_char *)mms->address + size;
+
+       if (mms->size == 0) {
+               RB_REMOVE(mmtree, &mm->rb_free, mms);
+               if (mm->mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mm->mmalloc, mms);
+       }
+
+       return (tmp->address);
+}
+
+/* Frees memory in a memory mapped area */
+
+void
+mm_free(struct mm_master *mm, void *address)
+{
+       struct mm_share *mms, *prev, tmp;
+
+       tmp.address = address;
+       mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp);
+       if (mms == NULL)
+               fatal("mm_free(%p): can not find %p", mm, address);
+
+       /* Debug */
+       memset(mms->address, 0xd0, mms->size);
+
+       /* Remove from allocated list and insert in free list */
+       RB_REMOVE(mmtree, &mm->rb_allocated, mms);
+       if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL)
+               fatal("mm_free(%p): double address %p", mm, address);
+
+       /* Find previous entry */
+       prev = mms;
+       if (RB_LEFT(prev, next)) {
+               prev = RB_LEFT(prev, next);
+               while (RB_RIGHT(prev, next))
+                       prev = RB_RIGHT(prev, next);
+       } else {
+               if (RB_PARENT(prev, next) &&
+                   (prev == RB_RIGHT(RB_PARENT(prev, next), next)))
+                       prev = RB_PARENT(prev, next);
+               else {
+                       while (RB_PARENT(prev, next) &&
+                           (prev == RB_LEFT(RB_PARENT(prev, next), next)))
+                               prev = RB_PARENT(prev, next);
+                       prev = RB_PARENT(prev, next);
+               }
+       }
+
+       /* Check if range does not overlap */
+       if (prev != NULL && MM_ADDRESS_END(prev) > address)
+               fatal("mm_free: memory corruption: %p(%d) > %p",
+                   prev->address, prev->size, address);
+
+       /* See if we can merge backwards */
+       if (prev != NULL && MM_ADDRESS_END(prev) == address) {
+               prev->size += mms->size;
+               RB_REMOVE(mmtree, &mm->rb_free, mms);
+               if (mm->mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mm->mmalloc, mms);
+       } else
+               prev = mms;
+
+       if (prev == NULL)
+               return;
+
+       /* Check if we can merge forwards */
+       mms = RB_NEXT(mmtree, &mm->rb_free, prev);
+       if (mms == NULL)
+               return;
+
+       if (MM_ADDRESS_END(prev) > mms->address)
+               fatal("mm_free: memory corruption: %p < %p(%d)",
+                   mms->address, prev->address, prev->size);
+       if (MM_ADDRESS_END(prev) != mms->address)
+               return;
+
+       prev->size += mms->size;
+       RB_REMOVE(mmtree, &mm->rb_free, mms);
+
+       if (mm->mmalloc == NULL)
+               xfree(mms);
+       else
+               mm_free(mm->mmalloc, mms);
+}
+
+static void
+mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree,
+    struct mm_master *mm, struct mm_master *mmold)
+{
+       struct mm_master *mmalloc = mm->mmalloc;
+       struct mm_share *mms, *new;
+
+       /* Sync free list */
+       RB_FOREACH(mms, mmtree, oldtree) {
+               /* Check the values */
+               mm_memvalid(mmold, mms, sizeof(struct mm_share));
+               mm_memvalid(mm, mms->address, mms->size);
+
+               new = mm_xmalloc(mmalloc, sizeof(struct mm_share));
+               memcpy(new, mms, sizeof(struct mm_share));
+               RB_INSERT(mmtree, newtree, new);
+       }
+}
+
+void
+mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc)
+{
+       struct mm_master *mm;
+       struct mm_master *mmalloc;
+       struct mm_master *mmold;
+       struct mmtree rb_free, rb_allocated;
+
+       debug3("%s: Share sync", __FUNCTION__);
+
+       mm = *pmm;
+       mmold = mm->mmalloc;
+       mm_memvalid(mmold, mm, sizeof(*mm));
+
+       mmalloc = mm_create(NULL, mm->size);
+       mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
+       memcpy(mm, *pmm, sizeof(struct mm_master));
+       mm->mmalloc = mmalloc;
+
+       rb_free = mm->rb_free;
+       rb_allocated = mm->rb_allocated;
+
+       RB_INIT(&mm->rb_free);
+       RB_INIT(&mm->rb_allocated);
+
+       mm_sync_list(&rb_free, &mm->rb_free, mm, mmold);
+       mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold);
+
+       mm_destroy(mmold);
+
+       *pmm = mm;
+       *pmmalloc = mmalloc;
+
+       debug3("%s: Share sync end", __FUNCTION__);
+}
+
+void
+mm_memvalid(struct mm_master *mm, void *address, size_t size)
+{
+       void *end = (u_char *)address + size;
+
+       if (address < mm->address)
+               fatal("mm_memvalid: address too small: %p", address);
+       if (end < address)
+               fatal("mm_memvalid: end < address: %p < %p", end, address);
+       if (end > (void *)((u_char *)mm->address + mm->size))
+               fatal("mm_memvalid: address too large: %p", address);
+}
diff --git a/monitor_mm.h b/monitor_mm.h
new file mode 100644 (file)
index 0000000..4344260
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MM_H_
+#define _MM_H_
+#include <sys/tree.h>
+
+struct mm_share {
+       RB_ENTRY(mm_share) next;
+       void *address;
+       size_t size;
+};
+
+struct mm_master {
+       RB_HEAD(mmtree, mm_share) rb_free;
+       struct mmtree rb_allocated;
+       void *address;
+       size_t size;
+
+       struct mm_master *mmalloc;      /* Used to completely share */
+
+       int write;              /* used to writing to other party */
+       int read;               /* used for reading from other party */
+};
+
+RB_PROTOTYPE(mmtree, mm_share, next, mm_compare)
+
+#define MM_MINSIZE             128
+
+#define MM_ADDRESS_END(x)      (void *)((u_char *)(x)->address + (x)->size)
+
+struct mm_master *mm_create(struct mm_master *, size_t);
+void mm_destroy(struct mm_master *);
+
+void mm_share_sync(struct mm_master **, struct mm_master **);
+
+void *mm_malloc(struct mm_master *, size_t);
+void *mm_xmalloc(struct mm_master *, size_t);
+void mm_free(struct mm_master *, void *);
+
+void mm_memvalid(struct mm_master *, void *, size_t);
+#endif /* _MM_H_ */
diff --git a/monitor_wrap.c b/monitor_wrap.c
new file mode 100644 (file)
index 0000000..e477cff
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2002 Markus Friedl <markus@openbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: monitor_wrap.c,v 1.4 2002/03/19 14:27:39 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+#include "ssh.h"
+#include "dh.h"
+#include "kex.h"
+#include "auth.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "packet.h"
+#include "mac.h"
+#include "log.h"
+#include "zlib.h"
+#include "monitor.h"
+#include "monitor_wrap.h"
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "monitor_fdpass.h"
+#include "getput.h"
+
+#include "auth.h"
+#include "channels.h"
+#include "session.h"
+
+/* Imports */
+extern int compat20;
+extern Newkeys *newkeys[];
+extern z_stream incoming_stream;
+extern z_stream outgoing_stream;
+extern struct monitor *monitor;
+extern Buffer input, output;
+
+void
+mm_request_send(int socket, enum monitor_reqtype type, Buffer *m)
+{
+       u_char buf[5];
+       u_int mlen = buffer_len(m);
+
+       debug3("%s entering: type %d", __FUNCTION__, type);
+
+       PUT_32BIT(buf, mlen + 1);
+       buf[4] = (u_char) type;         /* 1st byte of payload is mesg-type */
+       if (atomicio(write, socket, buf, sizeof(buf)) != sizeof(buf))
+               fatal("%s: write", __FUNCTION__);
+       if (atomicio(write, socket, buffer_ptr(m), mlen) != mlen)
+               fatal("%s: write", __FUNCTION__);
+}
+
+void
+mm_request_receive(int socket, Buffer *m)
+{
+       u_char buf[4];
+       ssize_t res;
+       u_int msg_len;
+
+       debug3("%s entering", __FUNCTION__);
+
+       res = atomicio(read, socket, buf, sizeof(buf));
+       if (res != sizeof(buf)) {
+               if (res == 0)
+                       fatal_cleanup();
+               fatal("%s: read: %d", __FUNCTION__, res);
+       }
+       msg_len = GET_32BIT(buf);
+       if (msg_len > 256 * 1024)
+               fatal("%s: read: bad msg_len %d", __FUNCTION__, msg_len);
+       buffer_clear(m);
+       buffer_append_space(m, msg_len);
+       res = atomicio(read, socket, buffer_ptr(m), msg_len);
+       if (res != msg_len)
+               fatal("%s: read: %d != msg_len", __FUNCTION__, res);
+}
+
+void
+mm_request_receive_expect(int socket, enum monitor_reqtype type, Buffer *m)
+{
+       u_char rtype;
+
+       debug3("%s entering: type %d", __FUNCTION__, type);
+
+       mm_request_receive(socket, m);
+       rtype = buffer_get_char(m);
+       if (rtype != type)
+               fatal("%s: read: rtype %d != type %d", __FUNCTION__,
+                   rtype, type);
+}
+
+DH *
+mm_choose_dh(int min, int nbits, int max)
+{
+       BIGNUM *p, *g;
+       int success = 0;
+       Buffer m;
+
+       buffer_init(&m);
+       buffer_put_int(&m, min);
+       buffer_put_int(&m, nbits);
+       buffer_put_int(&m, max);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_MODULI, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_MODULI", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_MODULI, &m);
+
+       success = buffer_get_char(&m);
+       if (success == 0)
+               fatal("%s: MONITOR_ANS_MODULI failed", __FUNCTION__);
+
+       if ((p = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __FUNCTION__);
+       if ((g = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __FUNCTION__);
+       buffer_get_bignum2(&m, p);
+       buffer_get_bignum2(&m, g);
+
+       debug3("%s: remaining %d", __FUNCTION__, buffer_len(&m));
+       buffer_free(&m);
+
+       return (dh_new_group(g, p));
+}
+
+int
+mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen)
+{
+       Kex *kex = *monitor->m_pkex;
+       Buffer m;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       buffer_put_int(&m, kex->host_key_index(key));
+       buffer_put_string(&m, data, datalen);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_SIGN, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_SIGN", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SIGN, &m);
+       *sigp  = buffer_get_string(&m, lenp);
+       buffer_free(&m);
+
+       return (0);
+}
+
+struct passwd *
+mm_getpwnamallow(const char *login)
+{
+       Buffer m;
+       struct passwd *pw;
+       u_int pwlen;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, login);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_PWNAM, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_PWNAM", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PWNAM, &m);
+
+       if (buffer_get_char(&m) == 0) {
+               buffer_free(&m);
+               return (NULL);
+       }
+       pw = buffer_get_string(&m, &pwlen);
+       if (pwlen != sizeof(struct passwd))
+               fatal("%s: struct passwd size mismatch", __FUNCTION__);
+       pw->pw_name = buffer_get_string(&m, NULL);
+       pw->pw_passwd = buffer_get_string(&m, NULL);
+       pw->pw_gecos = buffer_get_string(&m, NULL);
+       pw->pw_class = buffer_get_string(&m, NULL);
+       pw->pw_dir = buffer_get_string(&m, NULL);
+       pw->pw_shell = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       return (pw);
+}
+
+/* Inform the privileged process about service and style */
+
+void
+mm_inform_authserv(char *service, char *style)
+{
+       Buffer m;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, service);
+       buffer_put_cstring(&m, style ? style : "");
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m);
+
+       buffer_free(&m);
+}
+
+/* Do the password authentication */
+int
+mm_auth_password(Authctxt *authctxt, char *password)
+{
+       Buffer m;
+       int authenticated = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, password);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_AUTHPASSWORD, &m);
+
+       authenticated = buffer_get_int(&m);
+
+       buffer_free(&m);
+
+       debug3("%s: user %sauthenticated",
+           __FUNCTION__, authenticated ? "" : "not ");
+       return (authenticated);
+}
+
+int
+mm_user_key_allowed(struct passwd *pw, Key *key)
+{
+       return (mm_key_allowed(MM_USERKEY, NULL, NULL, key));
+}
+
+int
+mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host,
+    Key *key)
+{
+       return (mm_key_allowed(MM_HOSTKEY, user, host, key));
+}
+
+int
+mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
+    char *host, Key *key)
+{
+       int ret;
+
+       key->type = KEY_RSA; /* XXX hack for key_to_blob */
+       ret = mm_key_allowed(MM_RSAHOSTKEY, user, host, key);
+       key->type = KEY_RSA1;
+       return (ret);
+}
+
+static void
+mm_send_debug(Buffer *m)
+{
+       char *msg;
+
+       while (buffer_len(m)) {
+               msg = buffer_get_string(m, NULL);
+               debug3("%s: Sending debug: %s", __FUNCTION__, msg);
+               packet_send_debug("%s", msg);
+               xfree(msg);
+       }
+}
+
+int
+mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key)
+{
+       Buffer m;
+       u_char *blob;
+       u_int len;
+       int allowed = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       /* Convert the key to a blob and the pass it over */
+       if (!key_to_blob(key, &blob, &len))
+               return (0);
+
+       buffer_init(&m);
+       buffer_put_int(&m, type);
+       buffer_put_cstring(&m, user ? user : "");
+       buffer_put_cstring(&m, host ? host : "");
+       buffer_put_string(&m, blob, len);
+       xfree(blob);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m);
+
+       allowed = buffer_get_int(&m);
+
+       /* Send potential debug messages */
+       mm_send_debug(&m);
+
+       buffer_free(&m);
+
+       return (allowed);
+}
+
+/*
+ * This key verify needs to send the key type along, because the
+ * privileged parent makes the decision if the key is allowed
+ * for authentication.
+ */
+
+int
+mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
+{
+       Buffer m;
+       u_char *blob;
+       u_int len;
+       int verified = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       /* Convert the key to a blob and the pass it over */
+       if (!key_to_blob(key, &blob, &len))
+               return (0);
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, len);
+       buffer_put_string(&m, sig, siglen);
+       buffer_put_string(&m, data, datalen);
+       xfree(blob);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m);
+
+       verified = buffer_get_int(&m);
+
+       buffer_free(&m);
+
+       return (verified);
+}
+
+/* Export key state after authentication */
+Newkeys *
+mm_newkeys_from_blob(u_char *blob, int blen)
+{
+       Buffer b;
+       u_int len;
+       Newkeys *newkey = NULL;
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+
+       debug3("%s: %p(%d)", __FUNCTION__, blob, blen);
+#ifdef DEBUG_PK
+       dump_base64(stderr, blob, blen);
+#endif
+       buffer_init(&b);
+       buffer_append(&b, blob, blen);
+
+       newkey = xmalloc(sizeof(*newkey));
+       enc = &newkey->enc;
+       mac = &newkey->mac;
+       comp = &newkey->comp;
+
+       /* Enc structure */
+       enc->name = buffer_get_string(&b, NULL);
+       buffer_get(&b, &enc->cipher, sizeof(enc->cipher));
+       enc->enabled = buffer_get_int(&b);
+       enc->block_size = buffer_get_int(&b);
+       enc->key = buffer_get_string(&b, &enc->key_len);
+       enc->iv = buffer_get_string(&b, &len);
+       if (len != enc->block_size)
+               fatal("%s: bad ivlen: expected %d != %d", __FUNCTION__,
+                   enc->block_size, len);
+
+       if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher)
+               fatal("%s: bad cipher name %s or pointer %p", __FUNCTION__,
+                   enc->name, enc->cipher);
+
+       /* Mac structure */
+       mac->name = buffer_get_string(&b, NULL);
+       if (mac->name == NULL || mac_init(mac, mac->name) == -1)
+               fatal("%s: can not init mac %s", __FUNCTION__, mac->name);
+       mac->enabled = buffer_get_int(&b);
+       mac->key = buffer_get_string(&b, &len);
+       if (len > mac->key_len)
+               fatal("%s: bad mac key lenght: %d > %d", __FUNCTION__, len,
+                   mac->key_len);
+       mac->key_len = len;
+
+       /* Comp structure */
+       comp->type = buffer_get_int(&b);
+       comp->enabled = buffer_get_int(&b);
+       comp->name = buffer_get_string(&b, NULL);
+
+       len = buffer_len(&b);
+       if (len != 0)
+               error("newkeys_from_blob: remaining bytes in blob %d", len);
+       buffer_free(&b);
+       return (newkey);
+}
+
+int
+mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp)
+{
+       Buffer b;
+       int len;
+       u_char *buf;
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+       Newkeys *newkey = newkeys[mode];
+
+       debug3("%s: converting %p", __FUNCTION__, newkey);
+
+       if (newkey == NULL) {
+               error("%s: newkey == NULL", __FUNCTION__);
+               return 0;
+       }
+       enc = &newkey->enc;
+       mac = &newkey->mac;
+       comp = &newkey->comp;
+
+       buffer_init(&b);
+       /* Enc structure */
+       buffer_put_cstring(&b, enc->name);
+       /* The cipher struct is constant and shared, you export pointer */
+       buffer_append(&b, &enc->cipher, sizeof(enc->cipher));
+       buffer_put_int(&b, enc->enabled);
+       buffer_put_int(&b, enc->block_size);
+       buffer_put_string(&b, enc->key, enc->key_len);
+       packet_get_keyiv(mode, enc->iv, enc->block_size);
+       buffer_put_string(&b, enc->iv, enc->block_size);
+
+       /* Mac structure */
+       buffer_put_cstring(&b, mac->name);
+       buffer_put_int(&b, mac->enabled);
+       buffer_put_string(&b, mac->key, mac->key_len);
+
+       /* Comp structure */
+       buffer_put_int(&b, comp->type);
+       buffer_put_int(&b, comp->enabled);
+       buffer_put_cstring(&b, comp->name);
+
+       len = buffer_len(&b);
+       buf = xmalloc(len);
+       memcpy(buf, buffer_ptr(&b), len);
+       memset(buffer_ptr(&b), 0, len);
+       buffer_free(&b);
+       if (lenp != NULL)
+               *lenp = len;
+       if (blobp != NULL)
+               *blobp = buf;
+       return len;
+}
+
+static void
+mm_send_kex(Buffer *m, Kex *kex)
+{
+       buffer_put_string(m, kex->session_id, kex->session_id_len);
+       buffer_put_int(m, kex->we_need);
+       buffer_put_int(m, kex->hostkey_type);
+       buffer_put_int(m, kex->kex_type);
+       buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my));
+       buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer));
+       buffer_put_int(m, kex->flags);
+       buffer_put_cstring(m, kex->client_version_string);
+       buffer_put_cstring(m, kex->server_version_string);
+}
+
+void
+mm_send_keystate(struct monitor *monitor)
+{
+       Buffer m;
+       u_char *blob, *p;
+       u_int bloblen, plen;
+
+       buffer_init(&m);
+
+       if (!compat20) {
+               u_char iv[24];
+               int ivlen;
+
+               buffer_put_int(&m, packet_get_protocol_flags());
+
+               buffer_put_int(&m, packet_get_ssh1_cipher());
+
+               debug3("%s: Sending ssh1 IV", __FUNCTION__);
+               ivlen = packet_get_keyiv_len(MODE_OUT);
+               packet_get_keyiv(MODE_OUT, iv, ivlen);
+               buffer_put_string(&m, iv, ivlen);
+               ivlen = packet_get_keyiv_len(MODE_OUT);
+               packet_get_keyiv(MODE_IN, iv, ivlen);
+               buffer_put_string(&m, iv, ivlen);
+               goto skip;
+       } else {
+               /* Kex for rekeying */
+               mm_send_kex(&m, *monitor->m_pkex);
+       }
+
+       debug3("%s: Sending new keys: %p %p",
+           __FUNCTION__, newkeys[MODE_OUT], newkeys[MODE_IN]);
+
+       /* Keys from Kex */
+       if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen))
+               fatal("%s: conversion of newkeys failed", __FUNCTION__);
+
+       buffer_put_string(&m, blob, bloblen);
+       xfree(blob);
+
+       if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen))
+               fatal("%s: conversion of newkeys failed", __FUNCTION__);
+
+       buffer_put_string(&m, blob, bloblen);
+       xfree(blob);
+
+       buffer_put_int(&m, packet_get_seqnr(MODE_OUT));
+       buffer_put_int(&m, packet_get_seqnr(MODE_IN));
+
+       debug3("%s: New keys have been sent", __FUNCTION__);
+ skip:
+       /* More key context */
+       plen = packet_get_keycontext(MODE_OUT, NULL);
+       p = xmalloc(plen+1);
+       packet_get_keycontext(MODE_OUT, p);
+       buffer_put_string(&m, p, plen);
+       xfree(p);
+
+       plen = packet_get_keycontext(MODE_IN, NULL);
+       p = xmalloc(plen+1);
+       packet_get_keycontext(MODE_IN, p);
+       buffer_put_string(&m, p, plen);
+       xfree(p);
+
+       /* Compression state */
+       debug3("%s: Sending compression state", __FUNCTION__);
+       buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream));
+       buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream));
+
+       /* Network I/O buffers */
+       buffer_put_string(&m, buffer_ptr(&input), buffer_len(&input));
+       buffer_put_string(&m, buffer_ptr(&output), buffer_len(&output));
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m);
+       debug3("%s: Finished sending state", __FUNCTION__);
+
+       buffer_free(&m);
+}
+
+int
+mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
+{
+       Buffer m;
+       u_char *p;
+       int success = 0;
+
+       buffer_init(&m);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTY, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_PTY", __FUNCTION__);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PTY, &m);
+
+       success = buffer_get_int(&m);
+       if (success == 0) {
+               debug3("%s: pty alloc failed", __FUNCTION__);
+               buffer_free(&m);
+               return (0);
+       }
+       p = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       strlcpy(namebuf, p, namebuflen); /* Possible truncation */
+       xfree(p);
+
+       *ptyfd = mm_receive_fd(monitor->m_recvfd);
+       *ttyfd = mm_receive_fd(monitor->m_recvfd);
+
+       /* Success */
+       return (1);
+}
+
+void
+mm_session_pty_cleanup2(void *session)
+{
+       Session *s = session;
+       Buffer m;
+
+       if (s->ttyfd == -1)
+               return;
+       buffer_init(&m);
+       buffer_put_cstring(&m, s->tty);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, &m);
+       buffer_free(&m);
+
+       /* closed dup'ed master */
+       if (close(s->ptymaster) < 0)
+               error("close(s->ptymaster): %s", strerror(errno));
+
+       /* unlink pty from session */
+       s->ttyfd = -1;
+}
+
+/* Request process termination */
+
+void
+mm_terminate(void)
+{
+       Buffer m;
+
+       buffer_init(&m);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_TERM, &m);
+       buffer_free(&m);
+}
+
+int
+mm_ssh1_session_key(BIGNUM *num)
+{
+       int rsafail;
+       Buffer m;
+
+       buffer_init(&m);
+       buffer_put_bignum2(&m, num);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSKEY, &m);
+
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SESSKEY, &m);
+
+       rsafail = buffer_get_int(&m);
+       buffer_get_bignum2(&m, num);
+
+       buffer_free(&m);
+
+       return (rsafail);
+}
+
+static void
+mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
+    char ***prompts, u_int **echo_on)
+{
+       *name       = xstrdup("");
+       *infotxt    = xstrdup("");
+       *numprompts = 1;
+       *prompts = xmalloc(*numprompts * sizeof(char*));
+       *echo_on = xmalloc(*numprompts * sizeof(u_int));
+       (*echo_on)[0] = 0;
+}
+
+int
+mm_bsdauth_query(void *ctx, char **name, char **infotxt,
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+       Buffer m;
+       int res;
+       char *challenge;
+
+       debug3("%s: entering", __FUNCTION__);
+
+       buffer_init(&m);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m);
+
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY,
+           &m);
+       res = buffer_get_int(&m);
+       if (res == -1) {
+               debug3("%s: no challenge", __FUNCTION__);
+               buffer_free(&m);
+               return (-1);
+       }
+
+       /* Get the challenge, and format the response */
+       challenge  = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
+       (*prompts)[0] = challenge;
+
+       debug3("%s: received challenge: %s", __FUNCTION__, challenge);
+
+       return (0);
+}
+
+int
+mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Buffer m;
+       int authok;
+
+       debug3("%s: entering", __FUNCTION__);
+       if (numresponses != 1)
+               return (-1);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, responses[0]);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m);
+
+       mm_request_receive_expect(monitor->m_recvfd,
+           MONITOR_ANS_BSDAUTHRESPOND, &m);
+
+       authok = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return ((authok == 0) ? -1 : 0);
+}
+
+int
+mm_skey_query(void *ctx, char **name, char **infotxt,
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+       Buffer m;
+       int len, res;
+       char *p, *challenge;
+
+       debug3("%s: entering", __FUNCTION__);
+
+       buffer_init(&m);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m);
+
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SKEYQUERY,
+           &m);
+       res = buffer_get_int(&m);
+       if (res == -1) {
+               debug3("%s: no challenge", __FUNCTION__);
+               buffer_free(&m);
+               return (-1);
+       }
+
+       /* Get the challenge, and format the response */
+       challenge  = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       debug3("%s: received challenge: %s", __FUNCTION__, challenge);
+
+       mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
+
+       len = strlen(challenge) + strlen(SKEY_PROMPT) + 1;
+       p = xmalloc(len);
+       strlcpy(p, challenge, len);
+       strlcat(p, SKEY_PROMPT, len);
+       (*prompts)[0] = p;
+       xfree(challenge);
+
+       return (0);
+}
+
+int
+mm_skey_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Buffer m;
+       int authok;
+
+       debug3("%s: entering", __FUNCTION__);
+       if (numresponses != 1)
+               return (-1);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, responses[0]);
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m);
+
+       mm_request_receive_expect(monitor->m_recvfd,
+           MONITOR_ANS_SKEYRESPOND, &m);
+
+       authok = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return ((authok == 0) ? -1 : 0);
+}
+
+void
+mm_ssh1_session_id(u_char session_id[16])
+{
+       Buffer m;
+       int i;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       for (i = 0; i < 16; i++)
+               buffer_put_char(&m, session_id[i]);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSID, &m);
+       buffer_free(&m);
+}
+
+int
+mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
+{
+       Buffer m;
+       Key *key;
+       u_char *blob;
+       u_int blen;
+       int allowed = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       buffer_init(&m);
+       buffer_put_bignum2(&m, client_n);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m);
+
+       allowed = buffer_get_int(&m);
+
+       if (allowed && rkey != NULL) {
+               blob = buffer_get_string(&m, &blen);
+               if ((key = key_from_blob(blob, blen)) == NULL)
+                       fatal("%s: key_from_blob failed", __FUNCTION__);
+               *rkey = key;
+               xfree(blob);
+       }
+       mm_send_debug(&m);
+       buffer_free(&m);
+
+       return (allowed);
+}
+
+BIGNUM *
+mm_auth_rsa_generate_challenge(Key *key)
+{
+       Buffer m;
+       BIGNUM *challenge;
+       u_char *blob;
+       u_int blen;
+
+       debug3("%s entering", __FUNCTION__);
+
+       if ((challenge = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __FUNCTION__);
+
+       key->type = KEY_RSA;    /* XXX cheat for key_to_blob */
+       if (key_to_blob(key, &blob, &blen) == 0)
+               fatal("%s: key_to_blob failed", __FUNCTION__);
+       key->type = KEY_RSA1;
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, blen);
+       xfree(blob);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m);
+
+       buffer_get_bignum2(&m, challenge);
+       buffer_free(&m);
+
+       return (challenge);
+}
+
+int
+mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
+{
+       Buffer m;
+       u_char *blob;
+       u_int blen;
+       int success = 0;
+
+       debug3("%s entering", __FUNCTION__);
+
+       key->type = KEY_RSA;    /* XXX cheat for key_to_blob */
+       if (key_to_blob(key, &blob, &blen) == 0)
+               fatal("%s: key_to_blob failed", __FUNCTION__);
+       key->type = KEY_RSA1;
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, blen);
+       buffer_put_string(&m, response, 16);
+       xfree(blob);
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m);
+       mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m);
+
+       success = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return (success);
+}
diff --git a/monitor_wrap.h b/monitor_wrap.h
new file mode 100644 (file)
index 0000000..a75b905
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MM_WRAP_H_
+#define _MM_WRAP_H_
+#include "key.h"
+#include "buffer.h"
+
+extern int use_privsep;
+#define PRIVSEP(x)     (use_privsep ? mm_##x : x)
+
+enum mm_keytype {MM_NOKEY, MM_HOSTKEY, MM_USERKEY, MM_RSAHOSTKEY, MM_RSAUSERKEY};
+
+struct monitor;
+struct mm_master;
+struct passwd;
+struct Authctxt;
+
+DH *mm_choose_dh(int, int, int);
+int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+void mm_inform_authserv(char *, char *);
+struct passwd *mm_getpwnamallow(const char *);
+int mm_auth_password(struct Authctxt *, char *);
+int mm_key_allowed(enum mm_keytype, char *, char *, Key *);
+int mm_user_key_allowed(struct passwd *, Key *);
+int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
+int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
+int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
+int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
+int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
+BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+
+void mm_terminate(void);
+int mm_pty_allocate(int *, int *, char *, int);
+void mm_session_pty_cleanup2(void *);
+
+/* SSHv1 interfaces */
+void mm_ssh1_session_id(u_char *);
+int mm_ssh1_session_key(BIGNUM *);
+
+/* Key export functions */
+struct Newkeys *mm_newkeys_from_blob(u_char *, int);
+int mm_newkeys_to_blob(int, u_char **, u_int *);
+
+void monitor_apply_keystate(struct monitor *);
+void mm_get_keystate(struct monitor *);
+void mm_send_keystate(struct monitor*);
+
+/* bsdauth */
+int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_bsdauth_respond(void *, u_int, char **);
+
+/* skey */
+int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_skey_respond(void *, u_int, char **);
+
+/* zlib allocation hooks */
+
+void *mm_zalloc(struct mm_master *, u_int, u_int);
+void mm_zfree(struct mm_master *, void *);
+void mm_init_compression(struct mm_master *);
+
+#endif /* _MM_H_ */
index 9bbd994ca556417462dee5f9dbfcc79eeb4789b0..3b6b55e93f154dec8d58de4237fb07a43a8567d5 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.101 2002/02/04 12:15:25 markus Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.102 2002/03/18 17:50:31 provos Exp $");
 
 #if defined(KRB4) || defined(KRB5)
 #include <krb.h>
@@ -36,6 +36,8 @@ static void add_one_listen_addr(ServerOptions *, char *, u_short);
 
 /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;
+/* Use of privilege separation or not */
+extern int use_privsep;
 
 /* Initializes the server options to their default values. */
 
@@ -110,6 +112,13 @@ initialize_server_options(ServerOptions *options)
        options->client_alive_count_max = -1;
        options->authorized_keys_file = NULL;
        options->authorized_keys_file2 = NULL;
+
+       options->unprivileged_user = -1;
+       options->unprivileged_group = -1;
+       options->unprivileged_dir = NULL;
+
+       /* Needs to be accessable in many places */
+       use_privsep = -1;
 }
 
 void
@@ -235,6 +244,16 @@ fill_default_server_options(ServerOptions *options)
        }
        if (options->authorized_keys_file == NULL)
                options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
+
+       /* Turn privilege separation _off_ by default */
+       if (use_privsep == -1)
+               use_privsep = 0;
+       if (options->unprivileged_user == -1)
+               options->unprivileged_user = 32767;
+       if (options->unprivileged_group == -1)
+               options->unprivileged_group = 32767;
+       if (options->unprivileged_dir == NULL)
+               options->unprivileged_dir = "/var/empty";
 }
 
 /* Keyword tokens. */
@@ -267,6 +286,7 @@ typedef enum {
        sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
        sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
        sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+       sUsePrivilegeSeparation, sUnprivUser, sUnprivGroup, sUnprivDir,
        sDeprecated
 } ServerOpCodes;
 
@@ -342,6 +362,10 @@ static struct {
        { "clientalivecountmax", sClientAliveCountMax },
        { "authorizedkeysfile", sAuthorizedKeysFile },
        { "authorizedkeysfile2", sAuthorizedKeysFile2 },
+       { "useprivilegeseparation", sUsePrivilegeSeparation},
+       { "unprivuser", sUnprivUser},
+       { "unprivgroup", sUnprivGroup},
+       { "unprivdir", sUnprivDir},
        { NULL, sBadOption }
 };
 
@@ -718,6 +742,22 @@ parse_flag:
                intptr = &options->allow_tcp_forwarding;
                goto parse_flag;
 
+       case sUsePrivilegeSeparation:
+               intptr = &use_privsep;
+               goto parse_flag;
+
+       case sUnprivUser:
+               intptr = &options->unprivileged_user;
+               goto parse_flag;
+
+       case sUnprivGroup:
+               intptr = &options->unprivileged_group;
+               goto parse_flag;
+
+       case sUnprivDir:
+               charptr = &options->unprivileged_dir;
+               goto parse_filename;
+
        case sAllowUsers:
                while ((arg = strdelim(&cp)) && *arg != '\0') {
                        if (options->num_allow_users >= MAX_ALLOW_USERS)
index 3134b222a8c3999d944bbb02591fbee0cda2de54..b5d110a5a69c1f8d5e67b2d7eb647c9107778ffc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $   */
+/*     $OpenBSD: servconf.h,v 1.55 2002/03/18 17:50:31 provos Exp $    */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -131,6 +131,9 @@ typedef struct {
        char   *authorized_keys_file2;
        int     pam_authentication_via_kbd_int;
 
+       int     unprivileged_user;      /* User unprivileged child uses */
+       int     unprivileged_group;     /* Group unprivileged child uses */
+       char   *unprivileged_dir;       /* Chroot dir for unprivileged user */
 }       ServerOptions;
 
 void    initialize_server_options(ServerOptions *);
index 46b12ee3d3d73cde2992875d026bb0c865e8e648..f3a659188d34429ba6ec2ddb571648407f349bc4 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.98 2002/02/06 14:55:16 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.99 2002/03/18 17:50:31 provos Exp $");
 
 #include "xmalloc.h"
 #include "packet.h"
@@ -784,7 +784,7 @@ server_loop2(Authctxt *authctxt)
        channel_free_all();
 
        /* free remaining sessions, e.g. remove wtmp entries */
-       session_destroy_all();
+       session_destroy_all(NULL);
 }
 
 static void
index 29467029dc3059d42d7bc3a6c570bdeb866ed9d6..e5ea637d53ba33c50432ecc897d2bfb588722b3c 100644 (file)
--- a/session.c
+++ b/session.c
@@ -33,7 +33,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $");
+RCSID("$OpenBSD: session.c,v 1.130 2002/03/18 17:50:31 provos Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -56,6 +56,7 @@ RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $");
 #include "serverloop.h"
 #include "canohost.h"
 #include "session.h"
+#include "monitor_wrap.h"
 
 #ifdef HAVE_CYGWIN
 #include <windows.h>
@@ -63,39 +64,11 @@ RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $");
 #define is_winnt       (GetVersion() < 0x80000000)
 #endif
 
-/* types */
-
-#define TTYSZ 64
-typedef struct Session Session;
-struct Session {
-       int     used;
-       int     self;
-       struct passwd *pw;
-       Authctxt *authctxt;
-       pid_t   pid;
-       /* tty */
-       char    *term;
-       int     ptyfd, ttyfd, ptymaster;
-       int     row, col, xpixel, ypixel;
-       char    tty[TTYSZ];
-       /* X11 */
-       int     display_number;
-       char    *display;
-       int     screen;
-       char    *auth_display;
-       char    *auth_proto;
-       char    *auth_data;
-       int     single_connection;
-       /* proto 2 */
-       int     chanid;
-       int     is_subsystem;
-};
-
 /* func */
 
 Session *session_new(void);
 void   session_set_fds(Session *, int, int, int);
-static void    session_pty_cleanup(void *);
+void   session_pty_cleanup(void *);
 void   session_proctitle(Session *);
 int    session_setup_x11fwd(Session *);
 void   do_exec_pty(Session *, const char *);
@@ -112,7 +85,6 @@ int  check_quietlogin(Session *, const char *);
 static void do_authenticated1(Authctxt *);
 static void do_authenticated2(Authctxt *);
 
-static void session_close(Session *);
 static int session_pty_req(Session *);
 
 /* import */
@@ -1087,7 +1059,7 @@ do_nologin(struct passwd *pw)
 }
 
 /* Set login name, uid, gid, and groups. */
-static void
+void
 do_setusercontext(struct passwd *pw)
 {
 #ifdef HAVE_CYGWIN
@@ -1142,6 +1114,23 @@ do_setusercontext(struct passwd *pw)
                fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
 }
 
+void
+launch_login(struct passwd *pw, const char *hostname)
+{
+       /* Launch login(1). */
+
+       execl("/usr/bin/login", "login", "-h", hostname,
+#ifdef LOGIN_NEEDS_TERM
+                    (s->term ? s->term : "unknown"),
+#endif /* LOGIN_NEEDS_TERM */
+           "-p", "-f", "--", pw->pw_name, (char *)NULL);
+
+       /* Login couldn't be executed, die. */
+
+       perror("login");
+       exit(1);
+}
+
 /*
  * Performs common processing for the child, such as setting up the
  * environment, closing extra file descriptors, setting the user and group
@@ -1267,18 +1256,8 @@ do_child(Session *s, const char *command)
        signal(SIGPIPE,  SIG_DFL);
 
        if (options.use_login) {
-               /* Launch login(1). */
-
-               execl(LOGIN_PROGRAM, "login", "-h", hostname,
-#ifdef LOGIN_NEEDS_TERM
-                   (s->term ? s->term : "unknown"),
-#endif /* LOGIN_NEEDS_TERM */
-                   "-p", "-f", "--", pw->pw_name, (char *)NULL);
-
-               /* Login couldn't be executed, die. */
-
-               perror("login");
-               exit(1);
+               launch_login(pw, hostname);
+               /* NEVERREACHED */
        }
 
        /* Get the last component of the shell name. */
@@ -1388,6 +1367,22 @@ session_open(Authctxt *authctxt, int chanid)
        return 1;
 }
 
+Session *
+session_by_tty(char *tty)
+{
+       int i;
+       for (i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
+                       debug("session_by_tty: session %d tty %s", i, tty);
+                       return s;
+               }
+       }
+       debug("session_by_tty: unknown tty %.100s", tty);
+       session_dump();
+       return NULL;
+}
+
 static Session *
 session_by_channel(int id)
 {
@@ -1436,7 +1431,7 @@ session_pty_req(Session *s)
 {
        u_int len;
        int n_bytes;
-
+       
        if (no_pty_flag) {
                debug("Allocating a pty not permitted for this authentication.");
                return 0;
@@ -1465,7 +1460,7 @@ session_pty_req(Session *s)
 
        /* Allocate a pty and open it. */
        debug("Allocating pty.");
-       if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
+       if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) {
                if (s->term)
                        xfree(s->term);
                s->term = NULL;
@@ -1486,7 +1481,8 @@ session_pty_req(Session *s)
         * time in case we call fatal() (e.g., the connection gets closed).
         */
        fatal_add_cleanup(session_pty_cleanup, (void *)s);
-       pty_setowner(s->pw, s->tty);
+       if (!use_privsep)
+               pty_setowner(s->pw, s->tty);
 
        /* Set window size from the packet. */
        pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
@@ -1649,8 +1645,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
  * Function to perform pty cleanup. Also called if we get aborted abnormally
  * (e.g., due to a dropped connection).
  */
-static void
-session_pty_cleanup(void *session)
+void
+session_pty_cleanup2(void *session)
 {
        Session *s = session;
 
@@ -1668,7 +1664,8 @@ session_pty_cleanup(void *session)
                record_logout(s->pid, s->tty, s->pw->pw_name);
 
        /* Release the pseudo-tty. */
-       pty_release(s->tty);
+       if (getuid() == 0)
+               pty_release(s->tty);
 
        /*
         * Close the server side of the socket pairs.  We must do this after
@@ -1676,12 +1673,18 @@ session_pty_cleanup(void *session)
         * while we're still cleaning up.
         */
        if (close(s->ptymaster) < 0)
-               error("close(s->ptymaster): %s", strerror(errno));
+               error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
 
        /* unlink pty from session */
        s->ttyfd = -1;
 }
 
+void
+session_pty_cleanup(void *session)
+{
+       PRIVSEP(session_pty_cleanup2(session));
+}
+
 static void
 session_exit_message(Session *s, int status)
 {
@@ -1727,7 +1730,7 @@ session_exit_message(Session *s, int status)
        s->chanid = -1;
 }
 
-static void
+void
 session_close(Session *s)
 {
        debug("session_close: session %d pid %d", s->self, s->pid);
@@ -1794,13 +1797,17 @@ session_close_by_channel(int id, void *arg)
 }
 
 void
-session_destroy_all(void)
+session_destroy_all(void (*closefunc)(Session *))
 {
        int i;
        for (i = 0; i < MAX_SESSIONS; i++) {
                Session *s = &sessions[i];
-               if (s->used)
-                       session_close(s);
+               if (s->used) {
+                       if (closefunc != NULL)
+                               closefunc(s);
+                       else
+                               session_close(s);
+               }
        }
 }
 
index ec8284a5f68faf73b3ba8d72cbc42a125bb20ec5..81f024c9bf14e7d393d070b5db48c2cbacea5448 100644 (file)
--- a/session.h
+++ b/session.h
@@ -1,4 +1,4 @@
-/*     $OpenBSD: session.h,v 1.14 2002/02/03 17:53:25 markus Exp $     */
+/*     $OpenBSD: session.h,v 1.15 2002/03/18 17:50:31 provos Exp $     */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
 #ifndef SESSION_H
 #define SESSION_H
 
+#define TTYSZ 64
+typedef struct Session Session;
+struct Session {
+       int     used;
+       int     self;
+       struct passwd *pw;
+       Authctxt *authctxt;
+       pid_t   pid;
+       /* tty */
+       char    *term;
+       int     ptyfd, ttyfd, ptymaster;
+       int     row, col, xpixel, ypixel;
+       char    tty[TTYSZ];
+       /* X11 */
+       int     display_number;
+       char    *display;
+       int     screen;
+       char    *auth_display;
+       char    *auth_proto;
+       char    *auth_data;
+       int     single_connection;
+       /* proto 2 */
+       int     chanid;
+       int     is_subsystem;
+};
+
 void    do_authenticated(Authctxt *);
 
 int     session_open(Authctxt*, int);
 int     session_input_channel_req(Channel *, const char *);
 void    session_close_by_pid(pid_t, int);
 void    session_close_by_channel(int, void *);
-void    session_destroy_all(void);
+void    session_destroy_all(void (*)(Session *));
 
+Session        *session_new(void);
+Session        *session_by_tty(char *);
+void    session_close(Session *);
+void    do_setusercontext(struct passwd *);
 #endif
diff --git a/sshd.c b/sshd.c
index 0764588fc394ee0339c9b76cbca703f4134e89b6..c82603d5814f04f956643d3115342805a3270aec 100644 (file)
--- a/sshd.c
+++ b/sshd.c
  * called by a name other than "ssh" or "Secure Shell".
  *
  * SSH2 implementation:
+ * Privilege Separation:
  *
- * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2002 Niels Provos.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.231 2002/03/18 17:50:31 provos Exp $");
 
 #include <openssl/dh.h>
 #include <openssl/bn.h>
 #include <openssl/md5.h>
+#include <openssl/rand.h>
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -73,6 +76,10 @@ RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $");
 #include "dispatch.h"
 #include "channels.h"
 #include "session.h"
+#include "monitor_mm.h"
+#include "monitor.h"
+#include "monitor_wrap.h"
+#include "monitor_fdpass.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -190,8 +197,13 @@ u_int utmp_len = MAXHOSTNAMELEN;
 int *startup_pipes = NULL;
 int startup_pipe;              /* in child */
 
+/* variables used for privilege separation */
+extern struct monitor *monitor;
+extern int use_privsep;
+
 /* Prototypes for various functions defined later in this file. */
 void destroy_sensitive_data(void);
+void demote_sensitive_data(void);
 
 static void do_ssh1_kex(void);
 static void do_ssh2_kex(void);
@@ -478,6 +490,115 @@ destroy_sensitive_data(void)
        memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
 }
 
+/* Demote private to public keys for network child */
+void
+demote_sensitive_data(void)
+{
+       Key *tmp;
+       int i;
+
+       if (sensitive_data.server_key) {
+               tmp = key_demote(sensitive_data.server_key);
+               key_free(sensitive_data.server_key);
+               sensitive_data.server_key = tmp;
+       }
+
+       for (i = 0; i < options.num_host_key_files; i++) {
+               if (sensitive_data.host_keys[i]) {
+                       tmp = key_demote(sensitive_data.host_keys[i]);
+                       key_free(sensitive_data.host_keys[i]);
+                       sensitive_data.host_keys[i] = tmp;
+                       if (tmp->type == KEY_RSA1)
+                               sensitive_data.ssh1_host_key = tmp;
+               }
+       }
+
+       /* We do not clear ssh1_host key and cookie.  XXX - Okay Niels? */
+}
+
+void
+privsep_preauth_child(void)
+{
+       u_int32_t rand[256];
+       int i;
+
+       /* Enable challenge-response authentication for privilege separation */
+       privsep_challenge_enable();
+
+       for (i = 0; i < 256; i++)
+               rand[i] = arc4random();
+       RAND_seed(rand, sizeof(rand));
+
+       /* Demote the private keys to public keys. */
+       demote_sensitive_data();
+
+       /* Change our root directory*/
+       if (chroot(options.unprivileged_dir) == -1)
+               fatal("chroot(/var/empty)");
+       if (chdir("/") == -1)
+               fatal("chdir(/)");
+               
+       /* Drop our privileges */
+       setegid(options.unprivileged_group);
+       setgid(options.unprivileged_group);
+       seteuid(options.unprivileged_user);
+       setuid(options.unprivileged_user);
+}
+
+void
+privsep_postauth(Authctxt *authctxt, pid_t pid)
+{
+       extern Authctxt *x_authctxt;
+       int status;
+
+       /* Wait for the child's exit status */
+       waitpid(pid, &status, 0);
+
+       /* XXX - Remote port forwarding */
+       x_authctxt = authctxt;
+
+       if (authctxt->pw->pw_uid == 0 || options.use_login) {
+               /* File descriptor passing is broken or root login */
+               monitor_apply_keystate(monitor);
+               use_privsep = 0;
+               return;
+       }
+       
+       /* Authentication complete */
+       alarm(0);
+       if (startup_pipe != -1) {
+               close(startup_pipe);
+               startup_pipe = -1;
+       }
+
+       /* New socket pair */
+       monitor_reinit(monitor);
+
+       monitor->m_pid = fork();
+       if (monitor->m_pid == -1)
+               fatal("fork of unprivileged child failed");
+       else if (monitor->m_pid != 0) {
+               debug2("User child is on pid %d", pid);
+               close(monitor->m_recvfd);
+               monitor_child_postauth(monitor);
+
+               /* NEVERREACHED */
+               exit(0);
+       }
+
+       close(monitor->m_sendfd);
+
+       /* Demote the private keys to public keys. */
+       demote_sensitive_data();
+
+       /* Drop privileges */
+       do_setusercontext(authctxt->pw);
+
+       /* It is safe now to apply the key state */
+       monitor_apply_keystate(monitor);
+}
+
+
 static char *
 list_hostkey_types(void)
 {
@@ -507,7 +628,7 @@ list_hostkey_types(void)
        return p;
 }
 
-static Key *
+Key *
 get_hostkey_by_type(int type)
 {
        int i;
@@ -519,6 +640,25 @@ get_hostkey_by_type(int type)
        return NULL;
 }
 
+Key *
+get_hostkey_by_index(int ind)
+{
+       if (ind < 0 || ind >= options.num_host_key_files)
+               return (NULL);
+       return (sensitive_data.host_keys[ind]);
+}
+
+int
+get_hostkey_index(Key *key)
+{
+       int i;
+       for (i = 0; i < options.num_host_key_files; i++) {
+               if (key == sensitive_data.host_keys[i])
+                       return (i);
+       }
+       return (-1);
+}
+
 /*
  * returns 1 if connection should be dropped, 0 otherwise.
  * dropping starts at connection #max_startups_begin with a probability
@@ -1233,6 +1373,37 @@ main(int ac, char **av)
 
        packet_set_nonblocking();
 
+       if (!use_privsep)
+               goto skip_privilegeseparation;
+               
+       /* Set up unprivileged child process to deal with network data */
+       monitor = monitor_init();
+       /* Store a pointer to the kex for later rekeying */
+       monitor->m_pkex = &xxx_kex;
+
+       pid = fork();
+       if (pid == -1)
+               fatal("fork of unprivileged child failed");
+       else if (pid != 0) {
+               debug2("Network child is on pid %d", pid);
+
+               close(monitor->m_recvfd);
+               authctxt = monitor_child_preauth(monitor);
+               close(monitor->m_sendfd);
+
+               /* Sync memory */
+               monitor_sync(monitor);
+               goto authenticated;
+       } else {
+               close(monitor->m_sendfd);
+
+               /* Demote the child */
+               if (getuid() == 0 || geteuid() == 0)
+                       privsep_preauth_child();
+       }
+
+ skip_privilegeseparation:
+
        /* perform the key exchange */
        /* authenticate user and start session */
        if (compat20) {
@@ -1242,6 +1413,23 @@ main(int ac, char **av)
                do_ssh1_kex();
                authctxt = do_authentication();
        }
+       if (use_privsep)
+               mm_send_keystate(monitor);
+
+       /* If we use privilege separation, the unprivileged child exits */
+       if (use_privsep)
+               exit(0);
+
+ authenticated:
+       /* 
+        * In privilege separation, we fork another child and prepare
+        * file descriptor passing.
+        */
+       if (use_privsep) {
+               privsep_postauth(authctxt, pid);
+               if (!compat20)
+                       destroy_sensitive_data();
+       }
 
        /* Perform session preparation. */
        do_authenticated(authctxt);
@@ -1254,6 +1442,10 @@ main(int ac, char **av)
 #endif /* USE_PAM */
 
        packet_close();
+
+       if (use_privsep)
+               mm_terminate();
+
        exit(0);
 }
 
@@ -1261,7 +1453,7 @@ main(int ac, char **av)
  * Decrypt session_key_int using our private server key and private host key
  * (key with larger modulus first).
  */
-static int
+int
 ssh1_session_key(BIGNUM *session_key_int)
 {
        int rsafail = 0;
@@ -1417,7 +1609,8 @@ do_ssh1_kex(void)
        packet_check_eom();
 
        /* Decrypt session_key_int using host/server keys */
-       rsafail = ssh1_session_key(session_key_int);
+       rsafail = PRIVSEP(ssh1_session_key(session_key_int));
+
        /*
         * Extract session key from the decrypted integer.  The key is in the
         * least significant 256 bits of the integer; the first byte of the
@@ -1468,9 +1661,12 @@ do_ssh1_kex(void)
                for (i = 0; i < 16; i++)
                        session_id[i] = session_key[i] ^ session_key[i + 16];
        }
-       /* Destroy the private and public keys.  They will no longer be needed. */
+       /* Destroy the private and public keys. No longer. */
        destroy_sensitive_data();
 
+       if (use_privsep)
+               mm_ssh1_session_id(session_id);
+
        /* Destroy the decrypted integer.  It is no longer needed. */
        BN_clear_free(session_key_int);
 
@@ -1517,6 +1713,7 @@ do_ssh2_kex(void)
        kex->client_version_string=client_version_string;
        kex->server_version_string=server_version_string;
        kex->load_host_key=&get_hostkey_by_type;
+       kex->host_key_index=&get_hostkey_index;
 
        xxx_kex = kex;
 
This page took 0.256626 seconds and 5 git commands to generate.