diff options
-rw-r--r-- | usr.bin/ssh/auth-bsdauth.c | 15 | ||||
-rw-r--r-- | usr.bin/ssh/auth-options.c | 80 | ||||
-rw-r--r-- | usr.bin/ssh/auth-rh-rsa.c | 6 | ||||
-rw-r--r-- | usr.bin/ssh/auth-rsa.c | 17 | ||||
-rw-r--r-- | usr.bin/ssh/auth-skey.c | 17 | ||||
-rw-r--r-- | usr.bin/ssh/auth.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/auth1.c | 24 | ||||
-rw-r--r-- | usr.bin/ssh/auth2-chall.c | 21 | ||||
-rw-r--r-- | usr.bin/ssh/auth2.c | 43 | ||||
-rw-r--r-- | usr.bin/ssh/kex.c | 8 | ||||
-rw-r--r-- | usr.bin/ssh/kex.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/kexdh.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/kexgex.c | 9 | ||||
-rw-r--r-- | usr.bin/ssh/lib/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.c | 42 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/serverloop.c | 4 | ||||
-rw-r--r-- | usr.bin/ssh/session.c | 111 | ||||
-rw-r--r-- | usr.bin/ssh/session.h | 34 | ||||
-rw-r--r-- | usr.bin/ssh/sshd.c | 209 | ||||
-rw-r--r-- | usr.bin/ssh/sshd/Makefile | 4 |
21 files changed, 532 insertions, 134 deletions
diff --git a/usr.bin/ssh/auth-bsdauth.c b/usr.bin/ssh/auth-bsdauth.c index b70d48f20e0..fa06732cc2e 100644 --- a/usr.bin/ssh/auth-bsdauth.c +++ b/usr.bin/ssh/auth-bsdauth.c @@ -22,12 +22,13 @@ * 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 diff --git a/usr.bin/ssh/auth-options.c b/usr.bin/ssh/auth-options.c index 8df6a6dfcab..48be6d8e0f4 100644 --- a/usr.bin/ssh/auth-options.c +++ b/usr.bin/ssh/auth-options.c @@ -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; @@ -37,8 +43,27 @@ 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; } diff --git a/usr.bin/ssh/auth-rh-rsa.c b/usr.bin/ssh/auth-rh-rsa.c index 2a88e18b35e..c940ec581f0 100644 --- a/usr.bin/ssh/auth-rh-rsa.c +++ b/usr.bin/ssh/auth-rh-rsa.c @@ -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; diff --git a/usr.bin/ssh/auth-rsa.c b/usr.bin/ssh/auth-rsa.c index ff9bf3b6420..9c5d484b19e 100644 --- a/usr.bin/ssh/auth-rsa.c +++ b/usr.bin/ssh/auth-rsa.c @@ -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); } diff --git a/usr.bin/ssh/auth-skey.c b/usr.bin/ssh/auth-skey.c index df19f75072d..e897d18756e 100644 --- a/usr.bin/ssh/auth-skey.c +++ b/usr.bin/ssh/auth-skey.c @@ -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/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h index 727c70eea75..93b427f8c15 100644 --- a/usr.bin/ssh/auth.h +++ b/usr.bin/ssh/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. @@ -126,6 +126,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 *); @@ -152,4 +154,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/usr.bin/ssh/auth1.c b/usr.bin/ssh/auth1.c index 8b9b35e15cb..3252cb182ca 100644 --- a/usr.bin/ssh/auth1.c +++ b/usr.bin/ssh/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; @@ -84,7 +85,7 @@ do_authloop(Authctxt *authctxt) #if defined(KRB4) || defined(KRB5) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif - auth_password(authctxt, "")) { + PRIVSEP(auth_password(authctxt, ""))) { auth_log(authctxt, 1, "without authentication", ""); return; } @@ -243,7 +244,7 @@ do_authloop(Authctxt *authctxt) packet_check_eom(); /* Try authentication with the password. */ - authenticated = auth_password(authctxt, password); + authenticated = PRIVSEP(auth_password(authctxt, password)); memset(password, 0, strlen(password)); xfree(password); @@ -322,7 +323,7 @@ Authctxt * do_authentication(void) { Authctxt *authctxt; - struct passwd *pw; + struct passwd *pw = NULL, *pwent; u_int ulen; char *p, *user, *style = NULL; @@ -345,23 +346,28 @@ 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]" : ""); /* * If we are not running as root, the user must have the same uid as * the server. */ - 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."); /* diff --git a/usr.bin/ssh/auth2-chall.c b/usr.bin/ssh/auth2-chall.c index 9f1d932756b..38f955a022c 100644 --- a/usr.bin/ssh/auth2-chall.c +++ b/usr.bin/ssh/auth2-chall.c @@ -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/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c index 8ca920ea2c8..201e364e42a 100644 --- a/usr.bin/ssh/auth2.c +++ b/usr.bin/ssh/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); @@ -183,7 +184,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; @@ -191,10 +192,18 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) } else { log("input_userauth_request: illegal user %s", user); } - 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: " @@ -300,7 +309,7 @@ userauth_none(Authctxt *authctxt) m->enabled = NULL; packet_check_eom(); userauth_banner(); - return authctxt->valid ? auth_password(authctxt, "") : 0; + return (authctxt->valid ? PRIVSEP(auth_password(authctxt, "")) : 0); } static int @@ -316,7 +325,7 @@ userauth_passwd(Authctxt *authctxt) password = packet_get_string(&len); packet_check_eom(); if (authctxt->valid && - auth_password(authctxt, password) == 1) + PRIVSEP(auth_password(authctxt, password)) == 1) authenticated = 1; memset(password, 0, len); xfree(password); @@ -417,8 +426,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); @@ -434,7 +445,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); @@ -518,8 +529,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); @@ -676,7 +689,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; @@ -696,7 +709,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/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c index bf8fd95b4a2..8097ab0f263 100644 --- a/usr.bin/ssh/kex.c +++ b/usr.bin/ssh/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/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h index 755bf332aa4..2d3523a3633 100644 --- a/usr.bin/ssh/kex.h +++ b/usr.bin/ssh/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/usr.bin/ssh/kexdh.c b/usr.bin/ssh/kexdh.c index eaf497ca7f1..1e91e255022 100644 --- a/usr.bin/ssh/kexdh.c +++ b/usr.bin/ssh/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(); */ diff --git a/usr.bin/ssh/kexgex.c b/usr.bin/ssh/kexgex.c index 61896e6ed46..7379e8d103e 100644 --- a/usr.bin/ssh/kexgex.c +++ b/usr.bin/ssh/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/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile index dc1ec47eaaa..eabc9037da7 100644 --- a/usr.bin/ssh/lib/Makefile +++ b/usr.bin/ssh/lib/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.32 2002/03/08 01:53:56 itojun Exp $ +# $OpenBSD: Makefile,v 1.33 2002/03/18 17:50:31 provos Exp $ .PATH: ${.CURDIR}/.. @@ -9,7 +9,7 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \ rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \ key.c dispatch.c kex.c mac.c uuencode.c misc.c \ rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \ - scard.c + scard.c monitor_wrap.c monitor_fdpass.c DEBUGLIBS= no NOPROFILE= yes diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index cf2042e3100..4853beccf60 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -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. */ @@ -105,6 +107,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 @@ -225,6 +234,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. */ @@ -254,6 +273,7 @@ typedef enum { sBanner, sVerifyReverseMapping, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, + sUsePrivilegeSeparation, sUnprivUser, sUnprivGroup, sUnprivDir, sDeprecated } ServerOpCodes; @@ -326,6 +346,10 @@ static struct { { "clientalivecountmax", sClientAliveCountMax }, { "authorizedkeysfile", sAuthorizedKeysFile }, { "authorizedkeysfile2", sAuthorizedKeysFile2 }, + { "useprivilegeseparation", sUsePrivilegeSeparation}, + { "unprivuser", sUnprivUser}, + { "unprivgroup", sUnprivGroup}, + { "unprivdir", sUnprivDir}, { NULL, sBadOption } }; @@ -696,6 +720,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) diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 3cdb4491a20..5b99ea1aed3 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -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> @@ -130,6 +130,9 @@ typedef struct { char *authorized_keys_file; /* File containing public keys */ char *authorized_keys_file2; + 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 *); diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c index 5dd8a715ca9..09da1971bd3 100644 --- a/usr.bin/ssh/serverloop.c +++ b/usr.bin/ssh/serverloop.c @@ -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 diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c index ce5e3910ff9..8cf4b39ace0 100644 --- a/usr.bin/ssh/session.c +++ b/usr.bin/ssh/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,40 +56,13 @@ RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $"); #include "serverloop.h" #include "canohost.h" #include "session.h" - -/* 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; -}; +#include "monitor_wrap.h" /* 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 *); @@ -103,7 +76,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 */ @@ -935,7 +907,7 @@ do_nologin(struct passwd *pw) } /* Set login name, uid, gid, and groups. */ -static void +void do_setusercontext(struct passwd *pw) { if (getuid() == 0 || geteuid() == 0) { @@ -967,6 +939,20 @@ 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, + "-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 @@ -1083,15 +1069,8 @@ do_child(Session *s, const char *command) signal(SIGPIPE, SIG_DFL); if (options.use_login) { - /* Launch login(1). */ - - execl("/usr/bin/login", "login", "-h", hostname, - "-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. */ @@ -1201,6 +1180,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) { @@ -1249,7 +1244,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; @@ -1278,7 +1273,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; @@ -1299,7 +1294,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); @@ -1462,8 +1458,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; @@ -1481,7 +1477,8 @@ session_pty_cleanup(void *session) record_logout(s->pid, s->tty); /* 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 @@ -1489,12 +1486,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) { @@ -1536,7 +1539,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); @@ -1603,13 +1606,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); + } } } diff --git a/usr.bin/ssh/session.h b/usr.bin/ssh/session.h index ec8284a5f68..81f024c9bf1 100644 --- a/usr.bin/ssh/session.h +++ b/usr.bin/ssh/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. @@ -26,12 +26,42 @@ #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/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index 93a5f55faa2..dfc5176e5dc 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -15,8 +15,10 @@ * 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 @@ -40,11 +42,12 @@ */ #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> @@ -181,8 +188,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); @@ -469,6 +481,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) { @@ -498,7 +619,7 @@ list_hostkey_types(void) return p; } -static Key * +Key * get_hostkey_by_type(int type) { int i; @@ -510,6 +631,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 @@ -1205,6 +1345,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) { @@ -1214,6 +1385,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); @@ -1221,6 +1409,10 @@ main(int ac, char **av) /* The connection has been terminated. */ verbose("Closing connection to %.100s", remote_ip); packet_close(); + + if (use_privsep) + mm_terminate(); + exit(0); } @@ -1228,7 +1420,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; @@ -1384,7 +1576,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 @@ -1435,9 +1628,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); @@ -1484,6 +1680,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; diff --git a/usr.bin/ssh/sshd/Makefile b/usr.bin/ssh/sshd/Makefile index 8fdd8e6b676..8e495457854 100644 --- a/usr.bin/ssh/sshd/Makefile +++ b/usr.bin/ssh/sshd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.46 2002/03/05 00:49:51 deraadt Exp $ +# $OpenBSD: Makefile,v 1.47 2002/03/18 17:50:31 provos Exp $ .PATH: ${.CURDIR}/.. @@ -13,7 +13,7 @@ SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \ sshpty.c sshlogin.c servconf.c serverloop.c \ auth.c auth1.c auth2.c auth-options.c session.c \ auth-chall.c auth2-chall.c groupaccess.c \ - auth-skey.c auth-bsdauth.c + auth-skey.c auth-bsdauth.c monitor_mm.c monitor.c .include <bsd.own.mk> # for KERBEROS and AFS |