diff options
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | auth.h | 4 | ||||
-rw-r--r-- | auth1.c | 30 | ||||
-rw-r--r-- | auth2.c | 119 | ||||
-rw-r--r-- | bufaux.c | 2 | ||||
-rw-r--r-- | cipher.c | 40 | ||||
-rw-r--r-- | cipher.h | 2 | ||||
-rw-r--r-- | compress.c | 4 | ||||
-rw-r--r-- | kex.c | 4 | ||||
-rw-r--r-- | kex.h | 1 | ||||
-rw-r--r-- | kexdh.c | 13 | ||||
-rw-r--r-- | kexgex.c | 19 | ||||
-rw-r--r-- | key.c | 43 | ||||
-rw-r--r-- | key.h | 1 | ||||
-rw-r--r-- | monitor.c | 656 | ||||
-rw-r--r-- | monitor.h | 57 | ||||
-rw-r--r-- | monitor_fdpass.c | 89 | ||||
-rw-r--r-- | monitor_fdpass.h | 32 | ||||
-rw-r--r-- | monitor_mm.c | 329 | ||||
-rw-r--r-- | monitor_mm.h | 64 | ||||
-rw-r--r-- | monitor_wrap.c | 538 | ||||
-rw-r--r-- | monitor_wrap.h | 99 | ||||
-rw-r--r-- | packet.c | 106 | ||||
-rw-r--r-- | packet.h | 7 | ||||
-rw-r--r-- | servconf.c | 15 | ||||
-rw-r--r-- | session.c | 53 | ||||
-rw-r--r-- | session.h | 28 | ||||
-rw-r--r-- | sshd.c | 173 |
28 files changed, 2425 insertions, 109 deletions
diff --git a/Makefile.in b/Makefile.in index b58250aa..38c1d381 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.197 2002/02/26 19:24:22 mouring Exp $ +# $Id: Makefile.in,v 1.198 2002/03/13 01:47:54 djm Exp $ prefix=@prefix@ exec_prefix=@exec_prefix@ @@ -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 monitor_fdpass.c monitor_wrap.c 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 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 monitor.c monitor_mm.c sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.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 @@ -121,8 +121,8 @@ void krb5_cleanup_proc(void *authctxt); #include "auth-pam.h" #include "auth2-pam.h" -void do_authentication(void); -void do_authentication2(void); +Authctxt *do_authentication(void); +Authctxt *do_authentication2(void); Authctxt *authctxt_new(void); void auth_log(Authctxt *, int, char *, char *); @@ -26,8 +26,13 @@ RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $"); #include "session.h" #include "misc.h" #include "uidswap.h" +#include "monitor.h" +#include "monitor_wrap.h" /* import */ +extern int use_privsep; +extern int mm_recvfd; + extern ServerOptions options; /* @@ -355,12 +360,13 @@ do_authloop(Authctxt *authctxt) * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ -void +Authctxt * do_authentication(void) { Authctxt *authctxt; - struct passwd *pw; + struct passwd *pw = NULL, *pwent; u_int ulen; + int allowed; char *p, *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ @@ -382,17 +388,26 @@ do_authentication(void) authctxt->style = style; /* Verify that the user is a valid user. */ - pw = getpwnam(user); - if (pw && allowed_user(pw)) { + if (!use_privsep) { + pwent = getpwnam(user); + allowed = pwent ? allowed_user(pwent) : 0; + } else + pwent = mm_getpwnamallow(mm_recvfd, user, &allowed); + if (pwent && allowed) { authctxt->valid = 1; - pw = pwcopy(pw); + pw = pwcopy(pwent); } else { debug("do_authentication: illegal user %s", user); pw = NULL; } + /* Free memory */ + if (use_privsep) + pwfree(pwent); + authctxt->pw = pw; - setproctitle("%s", pw ? user : "unknown"); + setproctitle("%s%s", use_privsep ? " [net]" : "", + pw ? user : "unknown"); #ifdef USE_PAM start_pam(pw == NULL ? "NOUSER" : user); @@ -418,6 +433,5 @@ do_authentication(void) packet_send(); packet_write_wait(); - /* Perform session preparation. */ - do_authenticated(authctxt); + return (authctxt); } @@ -51,8 +51,13 @@ RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $"); #include "hostfile.h" #include "canohost.h" #include "match.h" +#include "monitor.h" +#include "monitor_wrap.h" /* import */ +extern int use_privsep; +extern int mm_recvfd; + extern ServerOptions options; extern u_char *session_id2; extern int session_id2_len; @@ -75,8 +80,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); @@ -109,7 +114,7 @@ Authmethod authmethods[] = { * loop until authctxt->success == TRUE */ -void +Authctxt * do_authentication2(void) { Authctxt *authctxt = authctxt_new(); @@ -125,7 +130,8 @@ do_authentication2(void) dispatch_init(&dispatch_protocol_error); dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); - do_authenticated(authctxt); + + return(authctxt); } static void @@ -182,10 +188,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) *style++ = 0; if (authctxt->attempt++ == 0) { - /* setup auth context */ + /* setup auth context */ + int allowed; struct passwd *pw = NULL; - pw = getpwnam(user); - if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { + if (!use_privsep) { + pw = getpwnam(user); + allowed = pw ? allowed_user(pw) : 0; + } else + pw = mm_getpwnamallow(mm_recvfd, user, &allowed); + if (pw && allowed && strcmp(service, "ssh-connection")==0) { authctxt->pw = pwcopy(pw); authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); @@ -198,10 +209,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) + pwfree(pw); + + setproctitle("%s%s", use_privsep ? " [net]" : "", + pw ? user : "unknown"); authctxt->user = xstrdup(user); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; + + if (use_privsep) + mm_inform_authserv(mm_recvfd, service, style); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of username or service not allowed: " @@ -313,6 +332,8 @@ done: static int userauth_none(Authctxt *authctxt) { + int res = 0; + /* disable method "none", only allowed one time */ Authmethod *m = authmethod_lookup("none"); if (m != NULL) @@ -322,18 +343,16 @@ userauth_none(Authctxt *authctxt) if (authctxt->valid == 0) return(0); - -#ifdef HAVE_CYGWIN - if (check_nt_auth(1, authctxt->pw) == 0) - return(0); + if (!authctxt->valid) + return (0); + if (use_privsep) +#if defined(USE_PAM) || defined(HAVE_OSF_SIA) +#error NOT IMPLEMENTED FOR PRIVSEP #endif -#ifdef USE_PAM - return auth_pam_password(authctxt->pw, ""); -#elif defined(HAVE_OSF_SIA) - return 0; -#else /* !HAVE_OSF_SIA && !USE_PAM */ - return auth_password(authctxt, ""); -#endif /* USE_PAM */ + res = mm_auth_password(mm_recvfd, ""); + else + res = auth_password(authctxt, ""); + return (res); } static int @@ -348,18 +367,16 @@ userauth_passwd(Authctxt *authctxt) log("password change not supported"); password = packet_get_string(&len); packet_check_eom(); - if (authctxt->valid && -#ifdef HAVE_CYGWIN - check_nt_auth(1, authctxt->pw) && + +#if defined(HAVE_CYGWIN) || defined(USE_PAM) || defined(HAVE_OSF_SIA) +#error NOT IMPLEMENTED FOR PRIVSEP #endif -#ifdef USE_PAM - auth_pam_password(authctxt->pw, password) == 1) -#elif defined(HAVE_OSF_SIA) - auth_sia_password(authctxt->user, password) == 1) -#else /* !USE_PAM && !HAVE_OSF_SIA */ - auth_password(authctxt, password) == 1) -#endif /* USE_PAM */ - authenticated = 1; + if (authctxt->valid) { + if (use_privsep) + authenticated = mm_auth_password(mm_recvfd, password); + else + authenticated = auth_password(authctxt, password); + } memset(password, 0, len); xfree(password); return authenticated; @@ -467,12 +484,23 @@ 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 = 1; + authenticated = 0; + if (use_privsep) { + if (mm_user_key_allowed(mm_recvfd, key) && + mm_key_verify(mm_recvfd, + MM_USERKEY, NULL, NULL, key, sig, slen, + buffer_ptr(&b), buffer_len(&b)) == 1) + authenticated = 1; + } else { + if (user_key_allowed(authctxt->pw, key) && + key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b)) == 1) + authenticated = 1; + } buffer_clear(&b); xfree(sig); } else { + int res = 0; debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); @@ -484,7 +512,11 @@ 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 (use_privsep) + res = mm_user_key_allowed(mm_recvfd, key); + else + res = user_key_allowed(authctxt->pw, key); + if (res) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); @@ -572,9 +604,18 @@ 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 = 1; + authenticated = 0; + if (use_privsep) { + if (mm_hostbased_key_allowed(mm_recvfd, cuser, chost, key) && + mm_key_verify(mm_recvfd, MM_HOSTKEY, cuser, chost, key, + sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) + authenticated = 1; + } else { + if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) && + key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b)) == 1) + authenticated = 1; + } buffer_clear(&b); done: @@ -730,7 +771,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; @@ -750,7 +791,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) { @@ -221,6 +221,8 @@ buffer_put_string(Buffer *buffer, const void *buf, u_int len) void buffer_put_cstring(Buffer *buffer, const char *s) { + if (s == NULL) + fatal("buffer_put_cstring: s == NULL"); buffer_put_string(buffer, s, strlen(s)); } @@ -541,3 +541,43 @@ evp_rijndael(void) #endif return (&rijndal_cbc); } + +/* + * Exports an IV from the CipherContext required to export the key + * state back from the unprivileged child to the privileged parent + * process. + */ + +void +cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) +{ + Cipher *c = cc->cipher; + u_char *civ = NULL; + int evplen; + + switch (c->number) { + case SSH_CIPHER_SSH2: + evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); + if (evplen == 0) + return; + if (evplen != len) + fatal("%s: wrong iv length %d != %d", __FUNCTION__, + evplen, len); + + if (strncmp(c->name, "aes", 3) == 0) { + struct ssh_rijndael_ctx *aesc; + + aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp); + if (aesc == NULL) + fatal("ssh_rijndael_cbc: no context"); + civ = aesc->r_iv; + } else { + civ = cc->evp.iv; + } + break; + default: + fatal("%s: bad cipher %d", __FUNCTION__, c->number); + } + memcpy(iv, civ, len); +} + @@ -81,4 +81,6 @@ void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); u_int cipher_blocksize(Cipher *); u_int cipher_keylen(Cipher *); + +void cipher_get_keyiv(CipherContext *, u_char *, u_int); #endif /* CIPHER_H */ @@ -19,8 +19,8 @@ RCSID("$OpenBSD: compress.c,v 1.17 2001/12/29 21:56:01 stevesk Exp $"); #include "zlib.h" #include "compress.h" -static z_stream incoming_stream; -static z_stream outgoing_stream; +z_stream incoming_stream; +z_stream outgoing_stream; static int compress_init_send_called = 0; static int compress_init_recv_called = 0; @@ -43,6 +43,10 @@ RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $"); #define KEX_COOKIE_LEN 16 +/* Use privilege separation for sshd */ +int use_privsep; +int mm_recvfd; + /* prototype */ static void kex_kexinit_finish(Kex *); static void kex_choose_conf(Kex *); @@ -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]); @@ -37,6 +37,12 @@ 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.h" +#include "monitor_wrap.h" + +/* Imports */ +extern int use_privsep; +extern int mm_recvfd; static u_char * kex_dh_hash( @@ -275,7 +281,12 @@ kexdh_server(Kex *kex) /* sign H */ /* XXX hashlen depends on KEX */ - key_sign(server_host_key, &signature, &slen, hash, 20); + if (use_privsep) + mm_key_sign(mm_recvfd, + kex->host_key_index(server_host_key), + &signature, &slen, hash, 20); + else + key_sign(server_host_key, &signature, &slen, hash, 20); /* destroy_sensitive_data(); */ @@ -38,6 +38,12 @@ 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.h" +#include "monitor_wrap.h" + +/* Imports */ +extern int use_privsep; +extern int mm_recvfd; static u_char * kexgex_hash( @@ -296,7 +302,11 @@ 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 */ + if (use_privsep) + dh = mm_choose_dh(mm_recvfd, min, nbits, max); + else + dh = choose_dh(min, nbits, max); if (dh == NULL) packet_disconnect("Protocol error: no matching DH grp found"); @@ -379,7 +389,11 @@ kexgex_server(Kex *kex) /* sign H */ /* XXX hashlen depends on KEX */ - key_sign(server_host_key, &signature, &slen, hash, 20); + if (use_privsep) + mm_key_sign(mm_recvfd, kex->host_key_index(server_host_key), + &signature, &slen, hash, 20); + else + key_sign(server_host_key, &signature, &slen, hash, 20); /* destroy_sensitive_data(); */ @@ -390,6 +404,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 */ @@ -801,3 +801,46 @@ key_verify( break; } } + +/* Converts a private to a public key */ + +Key * +key_demote(Key *k) +{ + Key *pk; + + pk = xmalloc(sizeof(*pk)); + pk->type = k->type; + pk->flags = k->flags; + pk->dsa = NULL; + pk->rsa = NULL; + + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((pk->rsa = RSA_new()) == NULL) + fatal("key_demote: RSA_new failed"); + if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + case KEY_DSA: + if ((pk->dsa = DSA_new()) == NULL) + fatal("key_demote: DSA_new failed"); + if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + + return (pk); +} @@ -58,6 +58,7 @@ struct Key { Key *key_new(int); Key *key_new_private(int); void key_free(Key *); +Key *key_demote(Key *); int key_equal(Key *, Key *); char *key_fingerprint(Key *, enum fp_type, enum fp_rep); char *key_type(Key *); diff --git a/monitor.c b/monitor.c new file mode 100644 index 00000000..b8579027 --- /dev/null +++ b/monitor.c @@ -0,0 +1,656 @@ +/* + * 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$"); + +#include <openssl/dh.h> + +#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 "log.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" + +/* Imports */ +extern Newkeys *current_keys[]; +extern z_stream incoming_stream; +extern z_stream outgoing_stream; +extern int compat20; +extern int mm_sendfd; + +/* State exported from the child */ + +struct { + z_stream incoming; + z_stream outgoing; + u_char *keyin; + u_int keyinlen; + u_char *keyout; + u_int keyoutlen; +} child_state; + +/* Prototype for authentication functions */ + +int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); +int user_key_allowed(struct passwd *, Key *); +Key *get_hostkey_by_index(int); + +void session_pty_cleanup(void *); + +static Authctxt *authctxt; + +struct mon_table { + enum monitor_reqtype type; + int flags; + int (*f)(int, Buffer *); +}; + +#define MON_PROTOONE 0x0001 /* Used in protocol 1 */ +#define MON_PROTOTWO 0x0002 /* Used in protocol 2 */ +#define MON_AUTH 0x0004 /* Authentication Request */ + +#define MON_BOTH (MON_PROTOONE|MON_PROTOTWO) + +#define MON_PERMIT 0x1000 /* Request is permitted */ + +struct mon_table mon_dispatch_proto20[] = { + {MONITOR_REQ_MODULI, MON_PROTOTWO, mm_answer_moduli}, + {MONITOR_REQ_SIGN, MON_PROTOTWO, mm_answer_sign}, + {MONITOR_REQ_PWNAM, MON_BOTH, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_BOTH, mm_answer_authserv}, + {MONITOR_REQ_AUTHPASSWORD, MON_BOTH | MON_AUTH, mm_answer_authpassword}, + {MONITOR_REQ_KEYALLOWED, MON_BOTH | MON_AUTH, mm_answer_keyallowed}, + {MONITOR_REQ_KEYVERIFY, MON_BOTH | MON_AUTH, mm_answer_keyverify}, + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_postauth20[] = { + {MONITOR_REQ_MODULI, MON_PROTOTWO, mm_answer_moduli}, + {MONITOR_REQ_SIGN, MON_PROTOTWO, mm_answer_sign}, + {MONITOR_REQ_PTY, MON_BOTH, mm_answer_pty}, + {MONITOR_REQ_TERM, MON_BOTH, mm_answer_term}, + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_proto15[] = { + {0, 0, NULL} +}; + +struct mon_table *mon_dispatch; + +/* Specifies if a certain message is allowed at the moment */ + +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++; + } +} + +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++; + } +} + +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + fatal("fcntl(%d, F_SETFD)", x); \ +} while (0) + +void +monitor_socketpair(int *pair) +{ + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, pair) == -1) + fatal("%s: socketpair", __FUNCTION__); + FD_CLOSEONEXEC(pair[0]); + FD_CLOSEONEXEC(pair[1]); +} + +Authctxt * +monitor_child_preauth(int socket) +{ + 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; + + authctxt = authctxt_new(); + + /* The first few requests do not require asynchronous access */ + for (;;) { + if (monitor_read(socket, mon_dispatch)) + break; + } + + debug("%s: %s has been authenticated by privileged process", + __FUNCTION__, authctxt->user); + + if (compat20) { + mm_get_keystate(socket); + } else { + fatal("Use loose"); + } + + return (authctxt); +} + +void +monitor_child_postauth(int socket) +{ + 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); + + if (!no_pty_flag) + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + } else + mon_dispatch = mon_dispatch_proto15; + + for (;;) { + if (monitor_read(socket, mon_dispatch)) + break; + } +} + +int +monitor_read(int socket, struct mon_table *ent) +{ + Buffer m; + int ret; + u_char type; + + buffer_init(&m); + + mm_request_receive(socket, &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)(socket, &m); + buffer_free(&m); + return ret; + } + + fatal("%s: unsupported request: %d\n", __FUNCTION__, type); + + /* NOTREACHED */ + return (-1); +} + +int +mm_answer_moduli(int socket, Buffer *m) +{ + DH *dh; + int min, want, max; + + /* Turn off requests for moduli */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 0); + + 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); + } |