summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2002-03-18 17:50:32 +0000
committerNiels Provos <provos@cvs.openbsd.org>2002-03-18 17:50:32 +0000
commit7ca5185f1594e5672a0ca06f6f77bb3299b40ae8 (patch)
tree83a59b74f9442e3ee6e97ce710c336bdc6907ca3 /usr.bin
parent82f5e3234e96afd04e5bf7f081b1abc58522db68 (diff)
integrate privilege separated openssh; its turned off by default for now.
work done by me and markus@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/auth-bsdauth.c15
-rw-r--r--usr.bin/ssh/auth-options.c80
-rw-r--r--usr.bin/ssh/auth-rh-rsa.c6
-rw-r--r--usr.bin/ssh/auth-rsa.c17
-rw-r--r--usr.bin/ssh/auth-skey.c17
-rw-r--r--usr.bin/ssh/auth.h5
-rw-r--r--usr.bin/ssh/auth1.c24
-rw-r--r--usr.bin/ssh/auth2-chall.c21
-rw-r--r--usr.bin/ssh/auth2.c43
-rw-r--r--usr.bin/ssh/kex.c8
-rw-r--r--usr.bin/ssh/kex.h3
-rw-r--r--usr.bin/ssh/kexdh.c5
-rw-r--r--usr.bin/ssh/kexgex.c9
-rw-r--r--usr.bin/ssh/lib/Makefile4
-rw-r--r--usr.bin/ssh/servconf.c42
-rw-r--r--usr.bin/ssh/servconf.h5
-rw-r--r--usr.bin/ssh/serverloop.c4
-rw-r--r--usr.bin/ssh/session.c111
-rw-r--r--usr.bin/ssh/session.h34
-rw-r--r--usr.bin/ssh/sshd.c209
-rw-r--r--usr.bin/ssh/sshd/Makefile4
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