summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2002-03-13 12:47:54 +1100
committerDamien Miller <djm@mindrot.org>2002-03-13 12:47:54 +1100
commit646e7cf3d7e7d4231c2d97d27c09fe5fe1d749e2 (patch)
treea693368c47d2d044514878fbb1516f87b487f78b
parent29bdd2c9bca2737e7a246ed50fd827a6ccba0c61 (diff)
Import of Niels Provos' 20020312 ssh-complete.diff
PAM, Cygwin and OSF SIA will not work for sure
-rw-r--r--Makefile.in6
-rw-r--r--auth.h4
-rw-r--r--auth1.c30
-rw-r--r--auth2.c119
-rw-r--r--bufaux.c2
-rw-r--r--cipher.c40
-rw-r--r--cipher.h2
-rw-r--r--compress.c4
-rw-r--r--kex.c4
-rw-r--r--kex.h1
-rw-r--r--kexdh.c13
-rw-r--r--kexgex.c19
-rw-r--r--key.c43
-rw-r--r--key.h1
-rw-r--r--monitor.c656
-rw-r--r--monitor.h57
-rw-r--r--monitor_fdpass.c89
-rw-r--r--monitor_fdpass.h32
-rw-r--r--monitor_mm.c329
-rw-r--r--monitor_mm.h64
-rw-r--r--monitor_wrap.c538
-rw-r--r--monitor_wrap.h99
-rw-r--r--packet.c106
-rw-r--r--packet.h7
-rw-r--r--servconf.c15
-rw-r--r--session.c53
-rw-r--r--session.h28
-rw-r--r--sshd.c173
28 files changed, 2425 insertions, 109 deletions
diff --git a/Makefile.in b/Makefile.in
index b58250aae..38c1d381c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.197 2002/02/26 19:24:22 mouring Exp $ 1# $Id: Makefile.in,v 1.198 2002/03/13 01:47:54 djm Exp $
2 2
3prefix=@prefix@ 3prefix=@prefix@
4exec_prefix=@exec_prefix@ 4exec_prefix=@exec_prefix@
@@ -50,11 +50,11 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
50 50
51TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS) 51TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS)
52 52
53LIBSSH_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 53LIBSSH_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
54 54
55SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o 55SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
56 56
57SSHDOBJS= 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 57SSHDOBJS= 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
58 58
59MANPAGES = 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 59MANPAGES = 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
60MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 60MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1
diff --git a/auth.h b/auth.h
index c7175405d..9b5b19f6c 100644
--- a/auth.h
+++ b/auth.h
@@ -121,8 +121,8 @@ void krb5_cleanup_proc(void *authctxt);
121#include "auth-pam.h" 121#include "auth-pam.h"
122#include "auth2-pam.h" 122#include "auth2-pam.h"
123 123
124void do_authentication(void); 124Authctxt *do_authentication(void);
125void do_authentication2(void); 125Authctxt *do_authentication2(void);
126 126
127Authctxt *authctxt_new(void); 127Authctxt *authctxt_new(void);
128void auth_log(Authctxt *, int, char *, char *); 128void auth_log(Authctxt *, int, char *, char *);
diff --git a/auth1.c b/auth1.c
index c2d99895f..c52f63897 100644
--- a/auth1.c
+++ b/auth1.c
@@ -26,8 +26,13 @@ RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $");
26#include "session.h" 26#include "session.h"
27#include "misc.h" 27#include "misc.h"
28#include "uidswap.h" 28#include "uidswap.h"
29#include "monitor.h"
30#include "monitor_wrap.h"
29 31
30/* import */ 32/* import */
33extern int use_privsep;
34extern int mm_recvfd;
35
31extern ServerOptions options; 36extern ServerOptions options;
32 37
33/* 38/*
@@ -355,12 +360,13 @@ do_authloop(Authctxt *authctxt)
355 * Performs authentication of an incoming connection. Session key has already 360 * Performs authentication of an incoming connection. Session key has already
356 * been exchanged and encryption is enabled. 361 * been exchanged and encryption is enabled.
357 */ 362 */
358void 363Authctxt *
359do_authentication(void) 364do_authentication(void)
360{ 365{
361 Authctxt *authctxt; 366 Authctxt *authctxt;
362 struct passwd *pw; 367 struct passwd *pw = NULL, *pwent;
363 u_int ulen; 368 u_int ulen;
369 int allowed;
364 char *p, *user, *style = NULL; 370 char *p, *user, *style = NULL;
365 371
366 /* Get the name of the user that we wish to log in as. */ 372 /* Get the name of the user that we wish to log in as. */
@@ -382,17 +388,26 @@ do_authentication(void)
382 authctxt->style = style; 388 authctxt->style = style;
383 389
384 /* Verify that the user is a valid user. */ 390 /* Verify that the user is a valid user. */
385 pw = getpwnam(user); 391 if (!use_privsep) {
386 if (pw && allowed_user(pw)) { 392 pwent = getpwnam(user);
393 allowed = pwent ? allowed_user(pwent) : 0;
394 } else
395 pwent = mm_getpwnamallow(mm_recvfd, user, &allowed);
396 if (pwent && allowed) {
387 authctxt->valid = 1; 397 authctxt->valid = 1;
388 pw = pwcopy(pw); 398 pw = pwcopy(pwent);
389 } else { 399 } else {
390 debug("do_authentication: illegal user %s", user); 400 debug("do_authentication: illegal user %s", user);
391 pw = NULL; 401 pw = NULL;
392 } 402 }
403 /* Free memory */
404 if (use_privsep)
405 pwfree(pwent);
406
393 authctxt->pw = pw; 407 authctxt->pw = pw;
394 408
395 setproctitle("%s", pw ? user : "unknown"); 409 setproctitle("%s%s", use_privsep ? " [net]" : "",
410 pw ? user : "unknown");
396 411
397#ifdef USE_PAM 412#ifdef USE_PAM
398 start_pam(pw == NULL ? "NOUSER" : user); 413 start_pam(pw == NULL ? "NOUSER" : user);
@@ -418,6 +433,5 @@ do_authentication(void)
418 packet_send(); 433 packet_send();
419 packet_write_wait(); 434 packet_write_wait();
420 435
421 /* Perform session preparation. */ 436 return (authctxt);
422 do_authenticated(authctxt);
423} 437}
diff --git a/auth2.c b/auth2.c
index f2a801ecc..f661f8d7c 100644
--- a/auth2.c
+++ b/auth2.c
@@ -51,8 +51,13 @@ RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $");
51#include "hostfile.h" 51#include "hostfile.h"
52#include "canohost.h" 52#include "canohost.h"
53#include "match.h" 53#include "match.h"
54#include "monitor.h"
55#include "monitor_wrap.h"
54 56
55/* import */ 57/* import */
58extern int use_privsep;
59extern int mm_recvfd;
60
56extern ServerOptions options; 61extern ServerOptions options;
57extern u_char *session_id2; 62extern u_char *session_id2;
58extern int session_id2_len; 63extern int session_id2_len;
@@ -75,8 +80,8 @@ static void input_userauth_request(int, u_int32_t, void *);
75/* helper */ 80/* helper */
76static Authmethod *authmethod_lookup(const char *); 81static Authmethod *authmethod_lookup(const char *);
77static char *authmethods_get(void); 82static char *authmethods_get(void);
78static int user_key_allowed(struct passwd *, Key *); 83int user_key_allowed(struct passwd *, Key *);
79static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); 84int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
80 85
81/* auth */ 86/* auth */
82static void userauth_banner(void); 87static void userauth_banner(void);
@@ -109,7 +114,7 @@ Authmethod authmethods[] = {
109 * loop until authctxt->success == TRUE 114 * loop until authctxt->success == TRUE
110 */ 115 */
111 116
112void 117Authctxt *
113do_authentication2(void) 118do_authentication2(void)
114{ 119{
115 Authctxt *authctxt = authctxt_new(); 120 Authctxt *authctxt = authctxt_new();
@@ -125,7 +130,8 @@ do_authentication2(void)
125 dispatch_init(&dispatch_protocol_error); 130 dispatch_init(&dispatch_protocol_error);
126 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 131 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
127 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 132 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
128 do_authenticated(authctxt); 133
134 return(authctxt);
129} 135}
130 136
131static void 137static void
@@ -182,10 +188,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
182 *style++ = 0; 188 *style++ = 0;
183 189
184 if (authctxt->attempt++ == 0) { 190 if (authctxt->attempt++ == 0) {
185 /* setup auth context */ 191 /* setup auth context */
192 int allowed;
186 struct passwd *pw = NULL; 193 struct passwd *pw = NULL;
187 pw = getpwnam(user); 194 if (!use_privsep) {
188 if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { 195 pw = getpwnam(user);
196 allowed = pw ? allowed_user(pw) : 0;
197 } else
198 pw = mm_getpwnamallow(mm_recvfd, user, &allowed);
199 if (pw && allowed && strcmp(service, "ssh-connection")==0) {
189 authctxt->pw = pwcopy(pw); 200 authctxt->pw = pwcopy(pw);
190 authctxt->valid = 1; 201 authctxt->valid = 1;
191 debug2("input_userauth_request: setting up authctxt for %s", user); 202 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)
198 start_pam("NOUSER"); 209 start_pam("NOUSER");
199#endif 210#endif
200 } 211 }
201 setproctitle("%s", pw ? user : "unknown"); 212 /* Free memory */
213 if (use_privsep)
214 pwfree(pw);
215
216 setproctitle("%s%s", use_privsep ? " [net]" : "",
217 pw ? user : "unknown");
202 authctxt->user = xstrdup(user); 218 authctxt->user = xstrdup(user);
203 authctxt->service = xstrdup(service); 219 authctxt->service = xstrdup(service);
204 authctxt->style = style ? xstrdup(style) : NULL; 220 authctxt->style = style ? xstrdup(style) : NULL;
221
222 if (use_privsep)
223 mm_inform_authserv(mm_recvfd, service, style);
205 } else if (strcmp(user, authctxt->user) != 0 || 224 } else if (strcmp(user, authctxt->user) != 0 ||
206 strcmp(service, authctxt->service) != 0) { 225 strcmp(service, authctxt->service) != 0) {
207 packet_disconnect("Change of username or service not allowed: " 226 packet_disconnect("Change of username or service not allowed: "
@@ -313,6 +332,8 @@ done:
313static int 332static int
314userauth_none(Authctxt *authctxt) 333userauth_none(Authctxt *authctxt)
315{ 334{
335 int res = 0;
336
316 /* disable method "none", only allowed one time */ 337 /* disable method "none", only allowed one time */
317 Authmethod *m = authmethod_lookup("none"); 338 Authmethod *m = authmethod_lookup("none");
318 if (m != NULL) 339 if (m != NULL)
@@ -322,18 +343,16 @@ userauth_none(Authctxt *authctxt)
322 343
323 if (authctxt->valid == 0) 344 if (authctxt->valid == 0)
324 return(0); 345 return(0);
325 346 if (!authctxt->valid)
326#ifdef HAVE_CYGWIN 347 return (0);
327 if (check_nt_auth(1, authctxt->pw) == 0) 348 if (use_privsep)
328 return(0); 349#if defined(USE_PAM) || defined(HAVE_OSF_SIA)
350#error NOT IMPLEMENTED FOR PRIVSEP
329#endif 351#endif
330#ifdef USE_PAM 352 res = mm_auth_password(mm_recvfd, "");
331 return auth_pam_password(authctxt->pw, ""); 353 else
332#elif defined(HAVE_OSF_SIA) 354 res = auth_password(authctxt, "");
333 return 0; 355 return (res);
334#else /* !HAVE_OSF_SIA && !USE_PAM */
335 return auth_password(authctxt, "");
336#endif /* USE_PAM */
337} 356}
338 357
339static int 358static int
@@ -348,18 +367,16 @@ userauth_passwd(Authctxt *authctxt)
348 log("password change not supported"); 367 log("password change not supported");
349 password = packet_get_string(&len); 368 password = packet_get_string(&len);
350 packet_check_eom(); 369 packet_check_eom();
351 if (authctxt->valid && 370
352#ifdef HAVE_CYGWIN 371#if defined(HAVE_CYGWIN) || defined(USE_PAM) || defined(HAVE_OSF_SIA)
353 check_nt_auth(1, authctxt->pw) && 372#error NOT IMPLEMENTED FOR PRIVSEP
354#endif 373#endif
355#ifdef USE_PAM 374 if (authctxt->valid) {
356 auth_pam_password(authctxt->pw, password) == 1) 375 if (use_privsep)
357#elif defined(HAVE_OSF_SIA) 376 authenticated = mm_auth_password(mm_recvfd, password);
358 auth_sia_password(authctxt->user, password) == 1) 377 else
359#else /* !USE_PAM && !HAVE_OSF_SIA */ 378 authenticated = auth_password(authctxt, password);
360 auth_password(authctxt, password) == 1) 379 }
361#endif /* USE_PAM */
362 authenticated = 1;
363 memset(password, 0, len); 380 memset(password, 0, len);
364 xfree(password); 381 xfree(password);
365 return authenticated; 382 return authenticated;
@@ -467,12 +484,23 @@ userauth_pubkey(Authctxt *authctxt)
467 buffer_dump(&b); 484 buffer_dump(&b);
468#endif 485#endif
469 /* test for correct signature */ 486 /* test for correct signature */
470 if (user_key_allowed(authctxt->pw, key) && 487 authenticated = 0;
471 key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 488 if (use_privsep) {
472 authenticated = 1; 489 if (mm_user_key_allowed(mm_recvfd, key) &&
490 mm_key_verify(mm_recvfd,
491 MM_USERKEY, NULL, NULL, key, sig, slen,
492 buffer_ptr(&b), buffer_len(&b)) == 1)
493 authenticated = 1;
494 } else {
495 if (user_key_allowed(authctxt->pw, key) &&
496 key_verify(key, sig, slen, buffer_ptr(&b),
497 buffer_len(&b)) == 1)
498 authenticated = 1;
499 }
473 buffer_clear(&b); 500 buffer_clear(&b);
474 xfree(sig); 501 xfree(sig);
475 } else { 502 } else {
503 int res = 0;
476 debug("test whether pkalg/pkblob are acceptable"); 504 debug("test whether pkalg/pkblob are acceptable");
477 packet_check_eom(); 505 packet_check_eom();
478 506
@@ -484,7 +512,11 @@ userauth_pubkey(Authctxt *authctxt)
484 * if a user is not allowed to login. is this an 512 * if a user is not allowed to login. is this an
485 * issue? -markus 513 * issue? -markus
486 */ 514 */
487 if (user_key_allowed(authctxt->pw, key)) { 515 if (use_privsep)
516 res = mm_user_key_allowed(mm_recvfd, key);
517 else
518 res = user_key_allowed(authctxt->pw, key);
519 if (res) {
488 packet_start(SSH2_MSG_USERAUTH_PK_OK); 520 packet_start(SSH2_MSG_USERAUTH_PK_OK);
489 packet_put_string(pkalg, alen); 521 packet_put_string(pkalg, alen);
490 packet_put_string(pkblob, blen); 522 packet_put_string(pkblob, blen);
@@ -572,9 +604,18 @@ userauth_hostbased(Authctxt *authctxt)
572 buffer_dump(&b); 604 buffer_dump(&b);
573#endif 605#endif
574 /* test for allowed key and correct signature */ 606 /* test for allowed key and correct signature */
575 if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) && 607 authenticated = 0;
576 key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 608 if (use_privsep) {
577 authenticated = 1; 609 if (mm_hostbased_key_allowed(mm_recvfd, cuser, chost, key) &&
610 mm_key_verify(mm_recvfd, MM_HOSTKEY, cuser, chost, key,
611 sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
612 authenticated = 1;
613 } else {
614 if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
615 key_verify(key, sig, slen, buffer_ptr(&b),
616 buffer_len(&b)) == 1)
617 authenticated = 1;
618 }
578 619
579 buffer_clear(&b); 620 buffer_clear(&b);
580done: 621done:
@@ -730,7 +771,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
730} 771}
731 772
732/* check whether given key is in .ssh/authorized_keys* */ 773/* check whether given key is in .ssh/authorized_keys* */
733static int 774int
734user_key_allowed(struct passwd *pw, Key *key) 775user_key_allowed(struct passwd *pw, Key *key)
735{ 776{
736 int success; 777 int success;
@@ -750,7 +791,7 @@ user_key_allowed(struct passwd *pw, Key *key)
750} 791}
751 792
752/* return 1 if given hostkey is allowed */ 793/* return 1 if given hostkey is allowed */
753static int 794int
754hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, 795hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
755 Key *key) 796 Key *key)
756{ 797{
diff --git a/bufaux.c b/bufaux.c
index 23bc0c814..64b9a26e9 100644
--- a/bufaux.c
+++ b/bufaux.c
@@ -221,6 +221,8 @@ buffer_put_string(Buffer *buffer, const void *buf, u_int len)
221void 221void
222buffer_put_cstring(Buffer *buffer, const char *s) 222buffer_put_cstring(Buffer *buffer, const char *s)
223{ 223{
224 if (s == NULL)
225 fatal("buffer_put_cstring: s == NULL");
224 buffer_put_string(buffer, s, strlen(s)); 226 buffer_put_string(buffer, s, strlen(s));
225} 227}
226 228
diff --git a/cipher.c b/cipher.c
index 9e8f42f5e..5ddf819c4 100644
--- a/cipher.c
+++ b/cipher.c
@@ -541,3 +541,43 @@ evp_rijndael(void)
541#endif 541#endif
542 return (&rijndal_cbc); 542 return (&rijndal_cbc);
543} 543}
544
545/*
546 * Exports an IV from the CipherContext required to export the key
547 * state back from the unprivileged child to the privileged parent
548 * process.
549 */
550
551void
552cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
553{
554 Cipher *c = cc->cipher;
555 u_char *civ = NULL;
556 int evplen;
557
558 switch (c->number) {
559 case SSH_CIPHER_SSH2:
560 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
561 if (evplen == 0)
562 return;
563 if (evplen != len)
564 fatal("%s: wrong iv length %d != %d", __FUNCTION__,
565 evplen, len);
566
567 if (strncmp(c->name, "aes", 3) == 0) {
568 struct ssh_rijndael_ctx *aesc;
569
570 aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
571 if (aesc == NULL)
572 fatal("ssh_rijndael_cbc: no context");
573 civ = aesc->r_iv;
574 } else {
575 civ = cc->evp.iv;
576 }
577 break;
578 default:
579 fatal("%s: bad cipher %d", __FUNCTION__, c->number);
580 }
581 memcpy(iv, civ, len);
582}
583
diff --git a/cipher.h b/cipher.h
index b3b0303c7..c7724469b 100644
--- a/cipher.h
+++ b/cipher.h
@@ -81,4 +81,6 @@ void cipher_cleanup(CipherContext *);
81void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); 81void cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
82u_int cipher_blocksize(Cipher *); 82u_int cipher_blocksize(Cipher *);
83u_int cipher_keylen(Cipher *); 83u_int cipher_keylen(Cipher *);
84
85void cipher_get_keyiv(CipherContext *, u_char *, u_int);
84#endif /* CIPHER_H */ 86#endif /* CIPHER_H */
diff --git a/compress.c b/compress.c
index 3badbf452..dec96ba55 100644
--- a/compress.c
+++ b/compress.c
@@ -19,8 +19,8 @@ RCSID("$OpenBSD: compress.c,v 1.17 2001/12/29 21:56:01 stevesk Exp $");
19#include "zlib.h" 19#include "zlib.h"
20#include "compress.h" 20#include "compress.h"
21 21
22static z_stream incoming_stream; 22z_stream incoming_stream;
23static z_stream outgoing_stream; 23z_stream outgoing_stream;
24static int compress_init_send_called = 0; 24static int compress_init_send_called = 0;
25static int compress_init_recv_called = 0; 25static int compress_init_recv_called = 0;
26 26
diff --git a/kex.c b/kex.c
index bf8fd95b4..e5c0b0d00 100644
--- a/kex.c
+++ b/kex.c
@@ -43,6 +43,10 @@ RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $");
43 43
44#define KEX_COOKIE_LEN 16 44#define KEX_COOKIE_LEN 16
45 45
46/* Use privilege separation for sshd */
47int use_privsep;
48int mm_recvfd;
49
46/* prototype */ 50/* prototype */
47static void kex_kexinit_finish(Kex *); 51static void kex_kexinit_finish(Kex *);
48static void kex_choose_conf(Kex *); 52static void kex_choose_conf(Kex *);
diff --git a/kex.h b/kex.h
index 755bf332a..c99afaec0 100644
--- a/kex.h
+++ b/kex.h
@@ -111,6 +111,7 @@ struct Kex {
111 char *server_version_string; 111 char *server_version_string;
112 int (*verify_host_key)(Key *); 112 int (*verify_host_key)(Key *);
113 Key *(*load_host_key)(int); 113 Key *(*load_host_key)(int);
114 int (*host_key_index)(Key *);
114}; 115};
115 116
116Kex *kex_setup(char *[PROPOSAL_MAX]); 117Kex *kex_setup(char *[PROPOSAL_MAX]);
diff --git a/kexdh.c b/kexdh.c
index eaf497ca7..6256722ff 100644
--- a/kexdh.c
+++ b/kexdh.c
@@ -37,6 +37,12 @@ RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $");
37#include "packet.h" 37#include "packet.h"
38#include "dh.h" 38#include "dh.h"
39#include "ssh2.h" 39#include "ssh2.h"
40#include "monitor.h"
41#include "monitor_wrap.h"
42
43/* Imports */
44extern int use_privsep;
45extern int mm_recvfd;
40 46
41static u_char * 47static u_char *
42kex_dh_hash( 48kex_dh_hash(
@@ -275,7 +281,12 @@ kexdh_server(Kex *kex)
275 281
276 /* sign H */ 282 /* sign H */
277 /* XXX hashlen depends on KEX */ 283 /* XXX hashlen depends on KEX */
278 key_sign(server_host_key, &signature, &slen, hash, 20); 284 if (use_privsep)
285 mm_key_sign(mm_recvfd,
286 kex->host_key_index(server_host_key),
287 &signature, &slen, hash, 20);
288 else
289 key_sign(server_host_key, &signature, &slen, hash, 20);
279 290
280 /* destroy_sensitive_data(); */ 291 /* destroy_sensitive_data(); */
281 292
diff --git a/kexgex.c b/kexgex.c
index 61896e6ed..3c811f337 100644
--- a/kexgex.c
+++ b/kexgex.c
@@ -38,6 +38,12 @@ RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $");
38#include "dh.h" 38#include "dh.h"
39#include "ssh2.h" 39#include "ssh2.h"
40#include "compat.h" 40#include "compat.h"
41#include "monitor.h"
42#include "monitor_wrap.h"
43
44/* Imports */
45extern int use_privsep;
46extern int mm_recvfd;
41 47
42static u_char * 48static u_char *
43kexgex_hash( 49kexgex_hash(
@@ -296,7 +302,11 @@ kexgex_server(Kex *kex)
296 fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 302 fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
297 min, nbits, max); 303 min, nbits, max);
298 304
299 dh = choose_dh(min, nbits, max); 305 /* Contact privileged parent */
306 if (use_privsep)
307 dh = mm_choose_dh(mm_recvfd, min, nbits, max);
308 else
309 dh = choose_dh(min, nbits, max);
300 if (dh == NULL) 310 if (dh == NULL)
301 packet_disconnect("Protocol error: no matching DH grp found"); 311 packet_disconnect("Protocol error: no matching DH grp found");
302 312
@@ -379,7 +389,11 @@ kexgex_server(Kex *kex)
379 389
380 /* sign H */ 390 /* sign H */
381 /* XXX hashlen depends on KEX */ 391 /* XXX hashlen depends on KEX */
382 key_sign(server_host_key, &signature, &slen, hash, 20); 392 if (use_privsep)
393 mm_key_sign(mm_recvfd, kex->host_key_index(server_host_key),
394 &signature, &slen, hash, 20);
395 else
396 key_sign(server_host_key, &signature, &slen, hash, 20);
383 397
384 /* destroy_sensitive_data(); */ 398 /* destroy_sensitive_data(); */
385 399
@@ -390,6 +404,7 @@ kexgex_server(Kex *kex)
390 packet_put_bignum2(dh->pub_key); /* f */ 404 packet_put_bignum2(dh->pub_key); /* f */
391 packet_put_string(signature, slen); 405 packet_put_string(signature, slen);
392 packet_send(); 406 packet_send();
407
393 xfree(signature); 408 xfree(signature);
394 xfree(server_host_key_blob); 409 xfree(server_host_key_blob);
395 /* have keys, free DH */ 410 /* have keys, free DH */
diff --git a/key.c b/key.c
index cda91571a..fb6bff95b 100644
--- a/key.c
+++ b/key.c
@@ -801,3 +801,46 @@ key_verify(
801 break; 801 break;
802 } 802 }
803} 803}
804
805/* Converts a private to a public key */
806
807Key *
808key_demote(Key *k)
809{
810 Key *pk;
811
812 pk = xmalloc(sizeof(*pk));
813 pk->type = k->type;
814 pk->flags = k->flags;
815 pk->dsa = NULL;
816 pk->rsa = NULL;
817
818 switch (k->type) {
819 case KEY_RSA1:
820 case KEY_RSA:
821 if ((pk->rsa = RSA_new()) == NULL)
822 fatal("key_demote: RSA_new failed");
823 if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL)
824 fatal("key_demote: BN_dup failed");
825 if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
826 fatal("key_demote: BN_dup failed");
827 break;
828 case KEY_DSA:
829 if ((pk->dsa = DSA_new()) == NULL)
830 fatal("key_demote: DSA_new failed");
831 if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL)
832 fatal("key_demote: BN_dup failed");
833 if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL)
834 fatal("key_demote: BN_dup failed");
835 if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL)
836 fatal("key_demote: BN_dup failed");
837 if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL)
838 fatal("key_demote: BN_dup failed");
839 break;
840 default:
841 fatal("key_free: bad key type %d", k->type);
842 break;
843 }
844
845 return (pk);
846}
diff --git a/key.h b/key.h
index a2257731a..bc8b3d06b 100644
--- a/key.h
+++ b/key.h
@@ -58,6 +58,7 @@ struct Key {
58Key *key_new(int); 58Key *key_new(int);
59Key *key_new_private(int); 59Key *key_new_private(int);
60void key_free(Key *); 60void key_free(Key *);
61Key *key_demote(Key *);
61int key_equal(Key *, Key *); 62int key_equal(Key *, Key *);
62char *key_fingerprint(Key *, enum fp_type, enum fp_rep); 63char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
63char *key_type(Key *); 64char *key_type(Key *);
diff --git a/monitor.c b/monitor.c
new file mode 100644
index 000000000..b85790271
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,656 @@
1/*
2 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD$");
28
29#include <openssl/dh.h>
30
31#include "ssh.h"
32#include "auth.h"
33#include "kex.h"
34#include "dh.h"
35#include "zlib.h"
36#include "packet.h"
37#include "auth-options.h"
38#include "sshpty.h"
39#include "channels.h"
40#include "session.h"
41#include "log.h"
42#include "monitor.h"
43#include "monitor_mm.h"
44#include "monitor_wrap.h"
45#include "monitor_fdpass.h"
46#include "xmalloc.h"
47#include "misc.h"
48#include "buffer.h"
49#include "bufaux.h"
50
51/* Imports */
52extern Newkeys *current_keys[];
53extern z_stream incoming_stream;
54extern z_stream outgoing_stream;
55extern int compat20;
56extern int mm_sendfd;
57
58/* State exported from the child */
59
60struct {
61 z_stream incoming;
62 z_stream outgoing;
63 u_char *keyin;
64 u_int keyinlen;
65 u_char *keyout;
66 u_int keyoutlen;
67} child_state;
68
69/* Prototype for authentication functions */
70
71int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
72int user_key_allowed(struct passwd *, Key *);
73Key *get_hostkey_by_index(int);
74
75void session_pty_cleanup(void *);
76
77static Authctxt *authctxt;
78
79struct mon_table {
80 enum monitor_reqtype type;
81 int flags;
82 int (*f)(int, Buffer *);
83};
84
85#define MON_PROTOONE 0x0001 /* Used in protocol 1 */
86#define MON_PROTOTWO 0x0002 /* Used in protocol 2 */
87#define MON_AUTH 0x0004 /* Authentication Request */
88
89#define MON_BOTH (MON_PROTOONE|MON_PROTOTWO)
90
91#define MON_PERMIT 0x1000 /* Request is permitted */
92
93struct mon_table mon_dispatch_proto20[] = {
94 {MONITOR_REQ_MODULI, MON_PROTOTWO, mm_answer_moduli},
95 {MONITOR_REQ_SIGN, MON_PROTOTWO, mm_answer_sign},
96 {MONITOR_REQ_PWNAM, MON_BOTH, mm_answer_pwnamallow},
97 {MONITOR_REQ_AUTHSERV, MON_BOTH, mm_answer_authserv},
98 {MONITOR_REQ_AUTHPASSWORD, MON_BOTH | MON_AUTH, mm_answer_authpassword},
99 {MONITOR_REQ_KEYALLOWED, MON_BOTH | MON_AUTH, mm_answer_keyallowed},
100 {MONITOR_REQ_KEYVERIFY, MON_BOTH | MON_AUTH, mm_answer_keyverify},
101 {0, 0, NULL}
102};
103
104struct mon_table mon_dispatch_postauth20[] = {
105 {MONITOR_REQ_MODULI, MON_PROTOTWO, mm_answer_moduli},
106 {MONITOR_REQ_SIGN, MON_PROTOTWO, mm_answer_sign},
107 {MONITOR_REQ_PTY, MON_BOTH, mm_answer_pty},
108 {MONITOR_REQ_TERM, MON_BOTH, mm_answer_term},
109 {0, 0, NULL}
110};
111
112struct mon_table mon_dispatch_proto15[] = {
113 {0, 0, NULL}
114};
115
116struct mon_table *mon_dispatch;
117
118/* Specifies if a certain message is allowed at the moment */
119
120void
121monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit)
122{
123 while (ent->f != NULL) {
124 if (ent->type == type) {
125 ent->flags &= ~MON_PERMIT;
126 ent->flags |= permit ? MON_PERMIT : 0;
127 return;
128 }
129 ent++;
130 }
131}
132
133void
134monitor_permit_authentications(int permit)
135{
136 struct mon_table *ent = mon_dispatch;
137
138 while (ent->f != NULL) {
139 if (ent->flags & MON_AUTH) {
140 ent->flags &= ~MON_PERMIT;
141 ent->flags |= permit ? MON_PERMIT : 0;
142 }
143 ent++;
144 }
145}
146
147#define FD_CLOSEONEXEC(x) do { \
148 if (fcntl(x, F_SETFD, 1) == -1) \
149 fatal("fcntl(%d, F_SETFD)", x); \
150} while (0)
151
152void
153monitor_socketpair(int *pair)
154{
155 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, pair) == -1)
156 fatal("%s: socketpair", __FUNCTION__);
157 FD_CLOSEONEXEC(pair[0]);
158 FD_CLOSEONEXEC(pair[1]);
159}
160
161Authctxt *
162monitor_child_preauth(int socket)
163{
164 debug3("preauth child monitor started");
165
166 if (compat20) {
167 mon_dispatch = mon_dispatch_proto20;
168
169 /* Permit requests for moduli and signatures */
170 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
171 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
172 } else
173 mon_dispatch = mon_dispatch_proto15;
174
175 authctxt = authctxt_new();
176
177 /* The first few requests do not require asynchronous access */
178 for (;;) {
179 if (monitor_read(socket, mon_dispatch))
180 break;
181 }
182
183 debug("%s: %s has been authenticated by privileged process",
184 __FUNCTION__, authctxt->user);
185
186 if (compat20) {
187 mm_get_keystate(socket);
188 } else {
189 fatal("Use loose");
190 }
191
192 return (authctxt);
193}
194
195void
196monitor_child_postauth(int socket)
197{
198 if (compat20) {
199 mon_dispatch = mon_dispatch_postauth20;
200
201 /* Permit requests for moduli and signatures */
202 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
203 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
204 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
205
206 if (!no_pty_flag)
207 monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
208 } else
209 mon_dispatch = mon_dispatch_proto15;
210
211 for (;;) {
212 if (monitor_read(socket, mon_dispatch))
213 break;
214 }
215}
216
217int
218monitor_read(int socket, struct mon_table *ent)
219{
220 Buffer m;
221 int ret;
222 u_char type;
223
224 buffer_init(&m);
225
226 mm_request_receive(socket, &m);
227 type = buffer_get_char(&m);
228
229 debug3("%s: checking request %d", __FUNCTION__, type);
230
231 while (ent->f != NULL) {
232 if (ent->type == type)
233 break;
234 ent++;
235 }
236
237 if (ent->f != NULL) {
238 if (!(ent->flags & MON_PERMIT))
239 fatal("%s: unpermitted request %d", __FUNCTION__,
240 type);
241 ret = (*ent->f)(socket, &m);
242 buffer_free(&m);
243 return ret;
244 }
245
246 fatal("%s: unsupported request: %d\n", __FUNCTION__, type);
247
248 /* NOTREACHED */
249 return (-1);
250}
251
252int
253mm_answer_moduli(int socket, Buffer *m)
254{
255 DH *dh;
256 int min, want, max;
257
258 /* Turn off requests for moduli */
259 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 0);
260
261 min = buffer_get_int(m);
262 want = buffer_get_int(m);
263 max = buffer_get_int(m);
264
265 debug3("%s: got parameters: %d %d %d",
266 __FUNCTION__, min, want, max);
267 /* We need to check here, too, in case the child got corrupted */
268 if (max < min || want < min || max < want)
269 fatal("%s: bad parameters: %d %d %d",
270 __FUNCTION__, min, want, max);
271
272 buffer_clear(m);
273
274 dh = choose_dh(min, want, max);
275 if (dh == NULL) {
276 buffer_put_char(m, 0);
277 return (0);
278 } else {
279 /* Send first bignum */
280 buffer_put_char(m, 1);
281 buffer_put_bignum2(m, dh->p);
282 buffer_put_bignum2(m, dh->g);
283
284 DH_free(dh);
285 }
286 mm_request_send(socket, MONITOR_ANS_MODULI, m);
287 return (0);
288}
289
290int
291mm_answer_sign(int socket, Buffer *m)
292{
293 Key *key;
294 u_char *p;
295 u_char *signature;
296 u_int siglen, datlen;
297 int keyid;
298
299 debug3("%s", __FUNCTION__);
300
301 keyid = buffer_get_int(m);
302 p = buffer_get_string(m, &datlen);
303
304 if ((key = get_hostkey_by_index(keyid)) == NULL)
305 fatal("%s: no hostkey from index %d", __FUNCTION__, keyid);
306 if (key_sign(key, &signature, &siglen, p, datlen) < 0)
307 fatal("%s: key_sign failed", __FUNCTION__);
308
309 debug3("%s: signature %p(%d)", __FUNCTION__, signature, siglen);
310
311 buffer_clear(m);
312 buffer_put_string(m, signature, siglen);
313
314 xfree(p);
315 xfree(signature);
316
317 /* Turn on permissions for getpwnam */
318 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
319
320 mm_request_send(socket, MONITOR_ANS_SIGN, m);
321 return (0);
322}
323
324/* Retrieves the password entry and also checks if the user is permitted */
325
326int
327mm_answer_pwnamallow(int socket, Buffer *m)
328{
329 char *login;
330 struct passwd *pwent;
331 int allowed;
332
333 debug3("%s", __FUNCTION__);
334
335 if (authctxt->attempt++ != 0)
336 fatal("%s: multiple attempts for getpwnam", __FUNCTION__);
337
338 login = buffer_get_string(m, NULL);
339
340 /* XXX - probably latch the username here */
341 pwent = getpwnam(login);
342 authctxt->user = xstrdup(login);
343 setproctitle("%s [priv]", pwent ? login : "unknown");
344 xfree(login);
345
346 /* Allow service/style information on the auth context */
347 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
348
349 buffer_clear(m);
350
351 if (pwent == NULL) {
352 buffer_put_char(m, 0);
353 mm_request_send(socket, MONITOR_ANS_PWNAM, m);
354 return (0);
355 }
356
357 /* Check if we permit this user */
358 allowed = allowed_user(pwent);
359
360 if (allowed) {
361 authctxt->pw = pwcopy(pwent);
362 authctxt->valid = 1;
363 }
364 buffer_put_char(m, allowed);
365 buffer_put_string(m, pwent, sizeof(struct passwd));
366 buffer_put_cstring(m, pwent->pw_name);
367 buffer_put_cstring(m, "*");
368 buffer_put_cstring(m, pwent->pw_gecos);
369 buffer_put_cstring(m, pwent->pw_class);
370 buffer_put_cstring(m, pwent->pw_dir);
371 buffer_put_cstring(m, pwent->pw_shell);
372
373 debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, allowed);
374 mm_request_send(socket, MONITOR_ANS_PWNAM, m);
375
376 return (0);
377}
378
379int
380mm_answer_authserv(int socket, Buffer *m)
381{
382 /* Disallow service/style information on the auth context */
383 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 0);
384
385 monitor_permit_authentications(1);
386
387 authctxt->service = buffer_get_string(m, NULL);
388 authctxt->style = buffer_get_string(m, NULL);
389 if (strlen(authctxt->style) == 0) {
390 xfree(authctxt->style);
391 authctxt->style = NULL;
392 }
393
394 debug3("%s: service=%s, style=%s",
395 __FUNCTION__, authctxt->service, authctxt->style);
396
397 return (0);
398}
399
400int
401mm_answer_authpassword(int socket, Buffer *m)
402{
403 char *passwd;
404 int authenticated;
405
406 passwd = buffer_get_string(m, NULL);
407 /* Only authenticate if the context is valid */
408 authenticated = authctxt->valid && auth_password(authctxt, passwd);
409 memset(passwd, 0, strlen(passwd));
410 xfree(passwd);
411
412 buffer_clear(m);
413 buffer_put_int(m, authenticated);
414
415 debug3("%s: sending result %d", __FUNCTION__, authenticated);
416 mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m);
417
418 /* Causes monitor loop to terminate if authenticated */
419 return (authenticated);
420}
421
422int
423mm_answer_keyallowed(int socket, Buffer *m)
424{
425 Key *key;
426 u_char *cuser, *chost, *blob;
427 u_int bloblen;
428 enum mm_keytype type = 0;
429 int allowed = 0;
430
431 debug3("%s entering", __FUNCTION__);
432
433 type = buffer_get_int(m);
434 cuser = buffer_get_string(m, NULL);
435 chost = buffer_get_string(m, NULL);
436 blob = buffer_get_string(m, &bloblen);
437
438 key = key_from_blob(blob, bloblen);
439
440 debug3("%s: key_from_blob: %p", __FUNCTION__, key);
441
442 if (key != NULL && authctxt->pw != NULL) {
443 switch(type) {
444 case MM_USERKEY:
445 allowed = user_key_allowed(authctxt->pw, key);
446 break;
447 case MM_HOSTKEY:
448 allowed = hostbased_key_allowed(authctxt->pw,
449 cuser, chost, key);
450 break;
451 default:
452 fatal("%s: unknown key type %d", __FUNCTION__,
453 type);
454 break;
455 }
456 key_free(key);
457 }
458 xfree(chost);
459 xfree(cuser);
460 xfree(blob);
461
462 debug3("%s: key %p is %s",
463 __FUNCTION__, key, allowed ? "allowed" : "disallowed");
464
465 buffer_clear(m);
466 buffer_put_int(m, allowed);
467
468 mm_request_send(socket, MONITOR_ANS_KEYALLOWED, m);
469 return (0);
470}
471
472int
473mm_answer_keyverify(int socket, Buffer *m)
474{
475 Key *key;
476 u_char *signature, *data, *cuser, *chost, *blob;
477 u_int signaturelen, datalen, bloblen;
478 int type;
479 int verified = 0;
480
481 type = buffer_get_int(m);
482 cuser = buffer_get_string(m, NULL);
483 chost = buffer_get_string(m, NULL);
484 blob = buffer_get_string(m, &bloblen);
485 signature = buffer_get_string(m, &signaturelen);
486 data = buffer_get_string(m, &datalen);
487
488 key = key_from_blob(blob, bloblen);
489 if (key == NULL)
490 fatal("%s: bad public key blob", __FUNCTION__);
491
492 if (authctxt->pw == NULL || !user_key_allowed(authctxt->pw, key))
493 fatal("%s: user not allowed", __FUNCTION__);
494 verified = key_verify(key, signature, signaturelen, data, datalen);
495 debug3("%s: key %p signature %s",
496 __FUNCTION__, key, verified ? "verified" : "unverified");
497
498 key_free(key);
499 xfree(chost);
500 xfree(cuser);
501 xfree(blob);
502 xfree(signature);
503 xfree(data);
504
505 buffer_clear(m);
506 buffer_put_int(m, verified);
507 mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m);
508
509 return (verified);
510}
511
512int
513mm_answer_pty(int socket, Buffer *m)
514{
515 Session *s;
516 int res;
517
518 debug3("%s entering", __FUNCTION__);
519
520 buffer_clear(m);
521 s = session_new();
522 if (s == NULL)
523 goto error;
524 s->authctxt = authctxt;
525 s->pw = authctxt->pw;
526 res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
527 if (res == 0)
528 goto error;
529 fatal_add_cleanup(session_pty_cleanup, (void *)s);
530 pty_setowner(authctxt->pw, s->tty);
531
532 buffer_put_int(m, 1);
533 buffer_put_cstring(m, s->tty);
534 mm_request_send(socket, MONITOR_ANS_PTY, m);
535
536 mm_send_fd(mm_sendfd, s->ptyfd);
537 mm_send_fd(mm_sendfd, s->ttyfd);
538 return (0);
539
540 error:
541 if (s != NULL)
542 session_close(s);
543 buffer_put_int(m, 0);
544 mm_request_send(socket, MONITOR_ANS_PTY, m);
545 return (0);
546}
547
548int
549mm_answer_term(int socket, Buffer *req)
550{
551 debug3("%s: tearing down sessions", __FUNCTION__);
552
553 /* The child is terminating */
554 session_destroy_all();
555
556 return (1);
557}
558
559void
560mm_apply_keystate(struct mm_master *mm)
561{
562 /* XXX - delegate to child? */
563 set_newkeys(MODE_IN);
564 set_newkeys(MODE_OUT);
565
566 packet_set_keycontext(MODE_OUT, child_state.keyout);
567 xfree(child_state.keyout);
568 packet_set_keycontext(MODE_IN, child_state.keyin);
569 xfree(child_state.keyin);
570
571 memcpy(&incoming_stream, &child_state.incoming,
572 sizeof(incoming_stream));
573 memcpy(&outgoing_stream, &child_state.outgoing,
574 sizeof(outgoing_stream));
575
576 /* Update with new address */
577 mm_init_compression(mm);
578}
579
580/* This function requries careful sanity checking */
581
582void
583mm_get_keystate(int socket)
584{
585 Buffer m;
586 u_char *blob, *p;
587 u_int bloblen, plen;
588
589 debug3("%s: Waiting for new keys", __FUNCTION__);
590
591 buffer_init(&m);
592 mm_request_receive_expect(socket, MONITOR_REQ_KEYEXPORT, &m);
593
594 blob = buffer_get_string(&m, &bloblen);
595 current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen);
596 xfree(blob);
597
598 debug3("%s: Waiting for second key", __FUNCTION__);
599 blob = buffer_get_string(&m, &bloblen);
600 current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen);
601 xfree(blob);
602
603 /* Now get sequence numbers for the packets */
604 packet_set_seqnr(MODE_OUT, buffer_get_int(&m));
605 packet_set_seqnr(MODE_IN, buffer_get_int(&m));
606
607 /* Get the key context */
608 child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen);
609 child_state.keyin = buffer_get_string(&m, &child_state.keyinlen);
610
611 debug3("%s: Getting compression state", __FUNCTION__);
612 /* Get compression state */
613 p = buffer_get_string(&m, &plen);
614 if (plen != sizeof(child_state.outgoing))
615 fatal("%s: bad request size", __FUNCTION__);
616 memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing));
617 xfree(p);
618
619 p = buffer_get_string(&m, &plen);
620 if (plen != sizeof(child_state.incoming))
621 fatal("%s: bad request size", __FUNCTION__);
622 memcpy(&child_state.incoming, p, sizeof(child_state.incoming));
623 xfree(p);
624
625 buffer_free(&m);
626}
627
628
629/* Allocation functions for zlib */
630void *
631mm_zalloc(struct mm_master *mm, u_int ncount, u_int size)
632{
633 void *address;
634
635 address = mm_malloc(mm, size * ncount);
636
637 return (address);
638}
639
640void
641mm_zfree(struct mm_master *mm, void *address)
642{
643 mm_free(mm, address);
644}
645
646void
647mm_init_compression(struct mm_master *mm)
648{
649 outgoing_stream.zalloc = (alloc_func)mm_zalloc;
650 outgoing_stream.zfree = (free_func)mm_zfree;
651 outgoing_stream.opaque = mm;
652
653 incoming_stream.zalloc = (alloc_func)mm_zalloc;
654 incoming_stream.zfree = (free_func)mm_zfree;
655 incoming_stream.opaque = mm;
656}
diff --git a/monitor.h b/monitor.h
new file mode 100644
index 000000000..7568603fe
--- /dev/null
+++ b/monitor.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef _MONITOR_H_
27#define _MONITOR_H_
28
29enum monitor_reqtype {
30 MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
31 MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
32 MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
33 MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
34 MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD,
35 MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
36 MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
37 MONITOR_REQ_KEYEXPORT,
38 MONITOR_REQ_PTY, MONITOR_ANS_PTY,
39 MONITOR_REQ_TERM
40};
41
42struct monitor_req {
43 enum monitor_reqtype type;
44 void *address;
45 size_t size;
46};
47
48void monitor_socketpair(int *pair);
49
50struct Authctxt;
51struct Authctxt *monitor_child_preauth(int);
52void monitor_child_postauth(int);
53
54struct mon_table;
55int monitor_read(int, struct mon_table *);
56
57#endif /* _MONITOR_H_ */
diff --git a/monitor_fdpass.c b/monitor_fdpass.c
new file mode 100644
index 000000000..46087ae66
--- /dev/null
+++ b/monitor_fdpass.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD$");
28
29#include <sys/uio.h>
30
31#include "ssh.h"
32#include "log.h"
33#include "xmalloc.h"
34#include "misc.h"
35#include "monitor_fdpass.h"
36
37void
38mm_send_fd(int socket, int fd)
39{
40 struct msghdr msg;
41 char tmp[CMSG_SPACE(sizeof(int))];
42 struct cmsghdr *cmsg;
43 struct iovec vec;
44 char ch;
45
46 memset(&msg, 0, sizeof(msg));
47 msg.msg_control = (caddr_t)tmp;
48 msg.msg_controllen = CMSG_LEN(sizeof(int));
49 cmsg = CMSG_FIRSTHDR(&msg);
50 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
51 cmsg->cmsg_level = SOL_SOCKET;
52 cmsg->cmsg_type = SCM_RIGHTS;
53 *(int *)CMSG_DATA(cmsg) = fd;
54
55 vec.iov_base = &ch;
56 vec.iov_len = 1;
57 msg.msg_iov = &vec;
58 msg.msg_iovlen = 1;
59
60 if (sendmsg(socket, &msg, 0) == -1)
61 fatal("%s: sendmsg(%d)", __FUNCTION__, fd);
62}
63
64int
65mm_receive_fd(int socket)
66{
67 struct msghdr msg;
68 char tmp[CMSG_SPACE(sizeof(int))];
69 struct cmsghdr *cmsg;
70 struct iovec vec;
71 char ch;
72
73 memset(&msg, 0, sizeof(msg));
74 vec.iov_base = &ch;
75 vec.iov_len = 1;
76 msg.msg_iov = &vec;
77 msg.msg_iovlen = 1;
78 msg.msg_control = tmp;
79 msg.msg_controllen = sizeof(tmp);
80
81 if (recvmsg(socket, &msg, 0) == -1)
82 fatal("%s: recvmsg", __FUNCTION__);
83
84 cmsg = CMSG_FIRSTHDR(&msg);
85 if (cmsg->cmsg_type != SCM_RIGHTS)
86 fatal("%s: expected type %d got %d", __FUNCTION__,
87 SCM_RIGHTS, cmsg->cmsg_type);
88 return (*(int *)CMSG_DATA(cmsg));
89}
diff --git a/monitor_fdpass.h b/monitor_fdpass.h
new file mode 100644
index 000000000..cb6b71c93
--- /dev/null
+++ b/monitor_fdpass.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef _MM_FDPASS_H_
27#define _MM_FDPASS_H_
28
29void mm_send_fd(int, int);
30int mm_receive_fd(int);
31
32#endif /* _MM_FDPASS_H_ */
diff --git a/monitor_mm.c b/monitor_mm.c
new file mode 100644
index 000000000..111c97d90
--- /dev/null
+++ b/monitor_mm.c
@@ -0,0 +1,329 @@
1/*
2 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD$");
28
29#include <sys/mman.h>
30
31#include "ssh.h"
32#include "xmalloc.h"
33#include "log.h"
34#include "monitor_mm.h"
35
36static int
37mm_compare(struct mm_share *a, struct mm_share *b)
38{
39 return (a->address - b->address);
40}
41
42RB_GENERATE(mmtree, mm_share, next, mm_compare);
43
44static struct mm_share *
45mm_make_entry(struct mm_master *mm, struct mmtree *head,
46 void *address, size_t size)
47{
48 struct mm_share *tmp, *tmp2;
49
50 if (mm->mmalloc == NULL)
51 tmp = xmalloc(sizeof(struct mm_share));
52 else
53 tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share));
54 tmp->address = address;
55 tmp->size = size;
56
57 tmp2 = RB_INSERT(mmtree, head, tmp);
58 if (tmp2 != NULL)
59 fatal("mm_make_entry(%p): double address %p->%p(%d)",
60 mm, tmp2, address, size);
61
62 return (tmp);
63}
64
65/* Creates a shared memory area of a certain size */
66
67struct mm_master *
68mm_create(struct mm_master *mmalloc, size_t size)
69{
70 void *address;
71 struct mm_master *mm;
72
73 if (mmalloc == NULL)
74 mm = xmalloc(sizeof(struct mm_master));
75 else
76 mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
77
78 /*
79 * If the memory map has a mm_master it can be completely
80 * shared including authentication between the child
81 * and the client.
82 */
83 mm->mmalloc = mmalloc;
84
85 address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED,
86 -1, 0);
87 if (address == MAP_FAILED)
88 fatal("mmap(%d)", size);
89
90 mm->address = address;
91 mm->size = size;
92
93 RB_INIT(&mm->rb_free);
94 RB_INIT(&mm->rb_allocated);
95
96 mm_make_entry(mm, &mm->rb_free, address, size);
97
98 return (mm);
99}
100
101/* Frees either the allocated or the free list */
102
103void
104mm_freelist(struct mm_master *mmalloc, struct mmtree *head)
105{
106 struct mm_share *mms, *next;
107
108 for (mms = RB_ROOT(head); mms; mms = next) {
109 next = RB_NEXT(mmtree, head, mms);
110 RB_REMOVE(mmtree, head, mms);
111 if (mmalloc == NULL)
112 xfree(mms);
113 else
114 mm_free(mmalloc, mms);
115 }
116}
117
118/* Destroys a memory mapped area */
119
120void
121mm_destroy(struct mm_master *mm)
122{
123 mm_freelist(mm->mmalloc, &mm->rb_free);
124 mm_freelist(mm->mmalloc, &mm->rb_allocated);
125
126 if (munmap(mm->address, mm->size) == -1)
127 fatal("munmap(%p, %d)", mm->address, mm->size);
128 if (mm->mmalloc == NULL)
129 xfree(mm);
130 else
131 mm_free(mm->mmalloc, mm);
132}
133
134void *
135mm_xmalloc(struct mm_master *mm, size_t size)
136{
137 void *address;
138
139 address = mm_malloc(mm, size);
140 if (address == NULL)
141 fatal("%s: mm_malloc(%d)", __FUNCTION__, size);
142 return (address);
143}
144
145
146/* Allocates data from a memory mapped area */
147
148void *
149mm_malloc(struct mm_master *mm, size_t size)
150{
151 struct mm_share *mms, *tmp;
152
153 if (size == 0)
154 fatal("mm_malloc: try to allocate 0 space");
155
156 size = ((size + MM_MINSIZE - 1) / MM_MINSIZE) * MM_MINSIZE;
157
158 RB_FOREACH(mms, mmtree, &mm->rb_free) {
159 if (mms->size >= size)
160 break;
161 }
162
163 if (mms == NULL)
164 return (NULL);
165
166 /* Debug */
167 memset(mms->address, 0xd0, size);
168
169 tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size);
170
171 /* Does not change order in RB tree */
172 mms->size -= size;
173 mms->address = (u_char *)mms->address + size;
174
175 if (mms->size == 0) {
176 RB_REMOVE(mmtree, &mm->rb_free, mms);
177 if (mm->mmalloc == NULL)
178 xfree(mms);
179 else
180 mm_free(mm->mmalloc, mms);
181 }
182
183 return (tmp->address);
184}
185
186/* Frees memory in a memory mapped area */
187
188void
189mm_free(struct mm_master *mm, void *address)
190{
191 struct mm_share *mms, *prev, tmp;
192
193 tmp.address = address;
194 mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp);
195 if (mms == NULL)
196 fatal("mm_free(%p): can not find %p", mm, address);
197
198 /* Debug */
199 memset(mms->address, 0xd0, mms->size);
200
201 /* Remove from allocated list and insert in free list */
202 RB_REMOVE(mmtree, &mm->rb_allocated, mms);
203 if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL)
204 fatal("mm_free(%p): double address %p", mm, address);
205
206 /* Find previous entry */
207 prev = mms;
208 if (RB_LEFT(prev, next)) {
209 prev = RB_LEFT(prev, next);
210 while (RB_RIGHT(prev, next))
211 prev = RB_RIGHT(prev, next);
212 } else {
213 if (RB_PARENT(prev, next) &&
214 (prev == RB_RIGHT(RB_PARENT(prev, next), next)))
215 prev = RB_PARENT(prev, next);
216 else {
217 while (RB_PARENT(prev, next) &&
218 (prev == RB_LEFT(RB_PARENT(prev, next), next)))
219 prev = RB_PARENT(prev, next);
220 prev = RB_PARENT(prev, next);
221 }
222 }
223
224 /* Check if range does not overlap */
225 if (prev != NULL && MM_ADDRESS_END(prev) > address)
226 fatal("mm_free: memory corruption: %p(%d) > %p",
227 prev->address, prev->size, address);
228
229 /* See if we can merge backwards */
230 if (prev != NULL && MM_ADDRESS_END(prev) == address) {
231 prev->size += mms->size;
232 RB_REMOVE(mmtree, &mm->rb_free, mms);
233 if (mm->mmalloc == NULL)
234 xfree(mms);
235 else
236 mm_free(mm->mmalloc, mms);
237 } else
238 prev = mms;
239
240 if (prev == NULL)
241 return;
242
243 /* Check if we can merge forwards */
244 mms = RB_NEXT(mmtree, &mm->rb_free, prev);
245 if (mms == NULL)
246 return;
247
248 if (MM_ADDRESS_END(prev) > mms->address)
249 fatal("mm_free: memory corruption: %p < %p(%d)",
250 mms->address, prev->address, prev->size);
251 if (MM_ADDRESS_END(prev) != mms->address)
252 return;
253
254 prev->size += mms->size;
255 RB_REMOVE(mmtree, &mm->rb_free, mms);
256
257 if (mm->mmalloc == NULL)
258 xfree(mms);
259 else
260 mm_free(mm->mmalloc, mms);
261}
262
263void
264mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree,
265 struct mm_master *mm, struct mm_master *mmold)
266{
267 struct mm_master *mmalloc = mm->mmalloc;
268 struct mm_share *mms, *new;
269
270 /* Sync free list */
271 RB_FOREACH(mms, mmtree, oldtree) {
272 /* Check the values */
273 mm_memvalid(mmold, mms, sizeof(struct mm_share));
274 mm_memvalid(mm, mms->address, mms->size);
275
276 new = mm_xmalloc(mmalloc, sizeof(struct mm_share));
277 memcpy(new, mms, sizeof(struct mm_share));
278 RB_INSERT(mmtree, newtree, new);
279 }
280}
281
282void
283mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc)
284{
285 struct mm_master *mm;
286 struct mm_master *mmalloc;
287 struct mm_master *mmold;
288 struct mmtree rb_free, rb_allocated;
289
290 debug3("%s: Share sync", __FUNCTION__);
291
292 mm = *pmm;
293 mmold = mm->mmalloc;
294 mm_memvalid(mmold, mm, sizeof(*mm));
295
296 mmalloc = mm_create(NULL, mm->size);
297 mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
298 memcpy(mm, *pmm, sizeof(struct mm_master));
299 mm->mmalloc = mmalloc;
300
301 rb_free = mm->rb_free;
302 rb_allocated = mm->rb_allocated;
303
304 RB_INIT(&mm->rb_free);
305 RB_INIT(&mm->rb_allocated);
306
307 mm_sync_list(&rb_free, &mm->rb_free, mm, mmold);
308 mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold);
309
310 mm_destroy(mmold);
311
312 *pmm = mm;
313 *pmmalloc = mmalloc;
314
315 debug3("%s: Share sync end", __FUNCTION__);
316}
317
318void
319mm_memvalid(struct mm_master *mm, void *address, size_t size)
320{
321 void *end = (u_char *)address + size;
322
323 if (address < mm->address)
324 fatal("mm_memvalid: address too small: %p", address);
325 if (end < address)
326 fatal("mm_memvalid: end < address: %p < %p", end, address);
327 if (end > (void *)((u_char *)mm->address + mm->size))
328 fatal("mm_memvalid: address too large: %p", address);
329}
diff --git a/monitor_mm.h b/monitor_mm.h
new file mode 100644
index 000000000..5b4b789ca
--- /dev/null
+++ b/monitor_mm.h
@@ -0,0 +1,64 @@
1/*
2 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef _MM_H_
27#define _MM_H_
28#include <sys/tree.h>
29
30struct mm_share {
31 RB_ENTRY(mm_share) next;
32 void *address;
33 size_t size;
34};
35
36struct mm_master {
37 RB_HEAD(mmtree, mm_share) rb_free;
38 struct mmtree rb_allocated;
39 void *address;
40 size_t size;
41
42 struct mm_master *mmalloc; /* Used to completely share */
43
44 int write; /* used to writing to other party */
45 int read; /* used for reading from other party */
46};
47
48RB_PROTOTYPE(mmtree, mm_share, next, mm_compare);
49
50#define MM_MINSIZE 128
51
52#define MM_ADDRESS_END(x) (void *)((u_char *)(x)->address + (x)->size)
53
54struct mm_master *mm_create(struct mm_master *, size_t);
55void mm_destroy(struct mm_master *);
56
57void mm_share_sync(struct mm_master **, struct mm_master **);
58
59void *mm_malloc(struct mm_master *, size_t);
60void *mm_xmalloc(struct mm_master *, size_t);
61void mm_free(struct mm_master *, void *);
62
63void mm_memvalid(struct mm_master *, void *, size_t);
64#endif /* _MM_H_ */
diff --git a/monitor_wrap.c b/monitor_wrap.c
new file mode 100644
index 000000000..798e9353d
--- /dev/null
+++ b/monitor_wrap.c
@@ -0,0 +1,538 @@
1/*
2 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD$");
28
29#include <openssl/bn.h>
30#include <openssl/dh.h>
31
32#include "ssh.h"
33#include "dh.h"
34#include "kex.h"
35#include "buffer.h"
36#include "bufaux.h"
37#include "packet.h"
38#include "mac.h"
39#include "log.h"
40#include "zlib.h"
41#include "monitor.h"
42#include "monitor_wrap.h"
43#include "xmalloc.h"
44#include "atomicio.h"
45#include "monitor_fdpass.h"
46#include "getput.h"
47
48/* Imports */
49extern Newkeys *newkeys[];
50extern z_stream incoming_stream;
51extern z_stream outgoing_stream;
52
53void
54mm_request_send(int socket, enum monitor_reqtype type, Buffer *m)
55{
56 u_char buf[5];
57 u_int mlen = buffer_len(m);
58
59 debug3("%s entering: type %d", __FUNCTION__, type);
60
61 PUT_32BIT(buf, mlen + 1);
62 buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */
63 if (atomicio(write, socket, buf, sizeof(buf)) != sizeof(buf))
64 fatal("%s: write", __FUNCTION__);
65 if (atomicio(write, socket, buffer_ptr(m), mlen) != mlen)
66 fatal("%s: write", __FUNCTION__);
67}
68
69void
70mm_request_receive(int socket, Buffer *m)
71{
72 u_char buf[4];
73 ssize_t res;
74 u_int msg_len;
75
76 debug3("%s entering", __FUNCTION__);
77
78 res = atomicio(read, socket, buf, sizeof(buf));
79 if (res != sizeof(buf))
80 fatal("%s: read: %d", __FUNCTION__, res);
81 msg_len = GET_32BIT(buf);
82 if (msg_len > 256 * 1024)
83 fatal("%s: read: bad msg_len %d", __FUNCTION__, msg_len);
84 buffer_clear(m);
85 buffer_append_space(m, msg_len);
86 res = atomicio(read, socket, buffer_ptr(m), msg_len);
87 if (res != msg_len)
88 fatal("%s: read: %d != msg_len", __FUNCTION__, res);
89}
90
91void
92mm_request_receive_expect(int socket, enum monitor_reqtype type, Buffer *m)
93{
94 u_char rtype;
95
96 debug3("%s entering: type %d", __FUNCTION__, type);
97
98 mm_request_receive(socket, m);
99 rtype = buffer_get_char(m);
100 if (rtype != type)
101 fatal("%s: read: rtype %d != type %d", __FUNCTION__,
102 rtype, type);
103}
104
105DH *
106mm_choose_dh(int socket, int min, int nbits, int max)
107{
108 BIGNUM *p, *g;
109 int success = 0;
110 Buffer m;
111
112 buffer_init(&m);
113 buffer_put_int(&m, min);
114 buffer_put_int(&m, nbits);
115 buffer_put_int(&m, max);
116
117 mm_request_send(socket, MONITOR_REQ_MODULI, &m);
118
119 debug3("%s: waiting for MONITOR_ANS_MODULI", __FUNCTION__);
120 mm_request_receive_expect(socket, MONITOR_ANS_MODULI, &m);
121
122 success = buffer_get_char(&m);
123 if (success == 0)
124 fatal("%s: MONITOR_ANS_MODULI failed", __FUNCTION__);
125
126 if ((p = BN_new()) == NULL)
127 fatal("%s: BN_new failed", __FUNCTION__);
128 if ((g = BN_new()) == NULL)
129 fatal("%s: BN_new failed", __FUNCTION__);
130 buffer_get_bignum2(&m, p);
131 buffer_get_bignum2(&m, g);
132
133 debug3("%s: remaining %d", __FUNCTION__, buffer_len(&m));
134 buffer_free(&m);
135
136 return (dh_new_group(g, p));
137}
138
139int
140mm_key_sign(int socket, int keyind, u_char **sigp, u_int *lenp,
141 u_char *data, u_int datalen)
142{
143 Buffer m;
144
145 debug3("%s entering", __FUNCTION__);
146
147 buffer_init(&m);
148 buffer_put_int(&m, keyind);
149 buffer_put_string(&m, data, datalen);
150
151 mm_request_send(socket, MONITOR_REQ_SIGN, &m);
152
153 debug3("%s: waiting for MONITOR_ANS_SIGN", __FUNCTION__);
154 mm_request_receive_expect(socket, MONITOR_ANS_SIGN, &m);
155 *sigp = buffer_get_string(&m, lenp);
156 buffer_free(&m);
157
158 return (0);
159}
160
161struct passwd *
162mm_getpwnamallow(int socket, const char *login, int *allowed)
163{
164 Buffer m;
165 struct passwd *pw;
166 u_int pwlen;
167
168 debug3("%s entering", __FUNCTION__);
169
170 buffer_init(&m);
171 buffer_put_cstring(&m, login);
172
173 mm_request_send(socket, MONITOR_REQ_PWNAM, &m);
174
175 debug3("%s: waiting for MONITOR_ANS_PWNAM", __FUNCTION__);
176 mm_request_receive_expect(socket, MONITOR_ANS_PWNAM, &m);
177
178 *allowed = buffer_get_char(&m);
179 if (*allowed == 0) {
180 buffer_free(&m);
181 return (NULL);
182 }
183 pw = buffer_get_string(&m, &pwlen);
184 if (pwlen != sizeof(struct passwd))
185 fatal("%s: struct passwd size mismatch", __FUNCTION__);
186 pw->pw_name = buffer_get_string(&m, NULL);
187 pw->pw_passwd = buffer_get_string(&m, NULL);
188 pw->pw_gecos = buffer_get_string(&m, NULL);
189 pw->pw_class = buffer_get_string(&m, NULL);
190 pw->pw_dir = buffer_get_string(&m, NULL);
191 pw->pw_shell = buffer_get_string(&m, NULL);
192 buffer_free(&m);
193
194 return (pw);
195}
196
197void
198pwfree(struct passwd *pw)
199{
200 xfree(pw->pw_name);
201 xfree(pw->pw_passwd);
202 xfree(pw->pw_gecos);
203 xfree(pw->pw_class);
204 xfree(pw->pw_dir);
205 xfree(pw->pw_shell);
206 xfree(pw);
207}
208
209/* Inform the privileged process about service and style */
210
211void
212mm_inform_authserv(int socket, char *service, char *style)
213{
214 Buffer m;
215
216 debug3("%s entering", __FUNCTION__);
217
218 buffer_init(&m);
219 buffer_put_cstring(&m, service);
220 buffer_put_cstring(&m, style ? style : "");
221
222 mm_request_send(socket, MONITOR_REQ_AUTHSERV, &m);
223
224 buffer_free(&m);
225}
226
227/* Do the password authentication */
228int
229mm_auth_password(int socket, char *password)
230{
231 Buffer m;
232 int authenticated = 0;
233
234 debug3("%s entering", __FUNCTION__);
235
236 buffer_init(&m);
237 buffer_put_cstring(&m, password);
238 mm_request_send(socket, MONITOR_REQ_AUTHPASSWORD, &m);
239
240 debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __FUNCTION__);
241 mm_request_receive_expect(socket, MONITOR_ANS_AUTHPASSWORD, &m);
242
243 authenticated = buffer_get_int(&m);
244
245 buffer_free(&m);
246
247 debug3("%s: user %sauthenticated",
248 __FUNCTION__, authenticated ? "" : "not ");
249 return (authenticated);
250}
251
252int
253mm_key_allowed(int socket, enum mm_keytype type, char *user, char *host,
254 Key *key)
255{
256 Buffer m;
257 u_char *blob;
258 u_int len;
259 int allowed = 0;
260
261 debug3("%s entering", __FUNCTION__);
262
263 /* Convert the key to a blob and the pass it over */
264 if (!key_to_blob(key, &blob, &len))
265 return (0);
266
267 buffer_init(&m);
268 buffer_put_int(&m, type);
269 buffer_put_cstring(&m, user ? user : "");
270 buffer_put_cstring(&m, host ? host : "");
271 buffer_put_string(&m, blob, len);
272 xfree(blob);
273
274 mm_request_send(socket, MONITOR_REQ_KEYALLOWED, &m);
275
276 debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __FUNCTION__);
277 mm_request_receive_expect(socket, MONITOR_ANS_KEYALLOWED, &m);
278
279 allowed = buffer_get_int(&m);
280
281 buffer_free(&m);
282
283 return (allowed);
284}
285
286/*
287 * This key verify needs to send the key type along, because the
288 * privileged parent makes the decision if the key is allowed
289 * for authentication.
290 */
291
292int
293mm_key_verify(int socket, enum mm_keytype type, char *user, char *host,
294 Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
295{
296 Buffer m;
297 u_char *blob;
298 u_int len;
299 int verified = 0;
300
301 debug3("%s entering", __FUNCTION__);
302
303 /* Convert the key to a blob and the pass it over */
304 if (!key_to_blob(key, &blob, &len))
305 return (0);
306
307 buffer_init(&m);
308 buffer_put_int(&m, type);
309 buffer_put_cstring(&m, user ? user : "");
310 buffer_put_cstring(&m, host ? host : "");
311 buffer_put_string(&m, blob, len);
312 buffer_put_string(&m, sig, siglen);
313 buffer_put_string(&m, data, datalen);
314 xfree(blob);
315
316 mm_request_send(socket, MONITOR_REQ_KEYVERIFY, &m);
317
318 debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __FUNCTION__);
319 mm_request_receive_expect(socket, MONITOR_ANS_KEYVERIFY, &m);
320
321 verified = buffer_get_int(&m);
322
323 buffer_free(&m);
324
325 return (verified);
326}
327
328/* Export key state after authentication */
329Newkeys *
330mm_newkeys_from_blob(u_char *blob, int blen)
331{
332 Buffer b;
333 int rlen;
334 Newkeys *newkey = NULL;
335 Enc *enc;
336 Mac *mac;
337 Comp *comp;
338
339 debug3("%s: %p(%d)", __FUNCTION__, blob, blen);
340#ifdef DEBUG_PK
341 dump_base64(stderr, blob, blen);
342#endif
343 buffer_init(&b);
344 buffer_append(&b, blob, blen);
345
346 newkey = xmalloc(sizeof(*newkey));
347 enc = &newkey->enc;
348 mac = &newkey->mac;
349 comp = &newkey->comp;
350
351 /* Enc structure */
352 enc->name = buffer_get_string(&b, NULL);
353 buffer_get(&b, &enc->cipher, sizeof(enc->cipher));
354 enc->enabled = buffer_get_int(&b);
355 enc->key_len = buffer_get_int(&b);
356 enc->block_size = buffer_get_int(&b);
357 enc->key = xmalloc(enc->key_len);
358 buffer_get(&b, enc->key, enc->key_len);
359 enc->iv = xmalloc(enc->block_size);
360 buffer_get(&b, enc->iv, enc->block_size);
361
362 if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher)
363 fatal("%s: bad cipher name %s or pointer %p", __FUNCTION__,
364 enc->name, enc->cipher);
365
366 /* Mac structure */
367 mac->name = buffer_get_string(&b, NULL);
368 if (mac->name == NULL || mac_init(mac, mac->name) == -1)
369 fatal("%s: can not init mac %s", __FUNCTION__, mac->name);
370 mac->enabled = buffer_get_int(&b);
371 mac->key = xmalloc(mac->key_len);
372 buffer_get(&b, mac->key, mac->key_len);
373
374 /* Comp structure */
375 comp->type = buffer_get_int(&b);
376 comp->enabled = buffer_get_int(&b);
377 comp->name = buffer_get_string(&b, NULL);
378
379 rlen = buffer_len(&b);
380 if (rlen != 0)
381 error("newkeys_from_blob: remaining bytes in blob %d", rlen);
382 buffer_free(&b);
383 return (newkey);
384}
385
386int
387mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp)
388{
389 Buffer b;
390 int len;
391 u_char *buf;
392 Enc *enc;
393 Mac *mac;
394 Comp *comp;
395 Newkeys *newkey = newkeys[mode];
396
397 debug3("%s: converting %p", __FUNCTION__, newkey);
398
399 if (newkey == NULL) {
400 error("%s: newkey == NULL", __FUNCTION__);
401 return 0;
402 }
403 enc = &newkey->enc;
404 mac = &newkey->mac;
405 comp = &newkey->comp;
406
407 buffer_init(&b);
408 /* Enc structure */
409 buffer_put_cstring(&b, enc->name);
410 /* The cipher struct is constant and shared, you export pointer */
411 buffer_append(&b, &enc->cipher, sizeof(enc->cipher));
412 buffer_put_int(&b, enc->enabled);
413 buffer_put_int(&b, enc->key_len);
414 buffer_put_int(&b, enc->block_size);
415 buffer_append(&b, enc->key, enc->key_len);
416 packet_get_keyiv(mode, enc->iv, enc->block_size);
417 buffer_append(&b, enc->iv, enc->block_size);
418
419 /* Mac structure */
420 buffer_put_cstring(&b, mac->name);
421 buffer_put_int(&b, mac->enabled);
422 buffer_append(&b, mac->key, mac->key_len);
423
424 /* Comp structure */
425 buffer_put_int(&b, comp->type);
426 buffer_put_int(&b, comp->enabled);
427 buffer_put_cstring(&b, comp->name);
428
429 len = buffer_len(&b);
430 buf = xmalloc(len);
431 memcpy(buf, buffer_ptr(&b), len);
432 memset(buffer_ptr(&b), 0, len);
433 buffer_free(&b);
434 if (lenp != NULL)
435 *lenp = len;
436 if (blobp != NULL)
437 *blobp = buf;
438 return len;
439}
440
441void
442mm_send_keystate(int socket)
443{
444 Buffer m;
445 u_char *blob, *p;
446 u_int bloblen, plen;
447
448 debug3("%s: Sending new keys: %p %p",
449 __FUNCTION__, newkeys[MODE_OUT], newkeys[MODE_IN]);
450
451 buffer_init(&m);
452
453 /* Keys from Kex */
454 if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen))
455 fatal("%s: conversion of newkeys failed", __FUNCTION__);
456
457 buffer_put_string(&m, blob, bloblen);
458 xfree(blob);
459
460 if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen))
461 fatal("%s: conversion of newkeys failed", __FUNCTION__);
462
463 buffer_put_string(&m, blob, bloblen);
464 xfree(blob);
465
466 buffer_put_int(&m, packet_get_seqnr(MODE_OUT));
467 buffer_put_int(&m, packet_get_seqnr(MODE_IN));
468
469 debug3("%s: New keys have been sent", __FUNCTION__);
470
471 /* More key context */
472 plen = packet_get_keycontext(MODE_OUT, NULL);
473 p = xmalloc(plen+1);
474 packet_get_keycontext(MODE_OUT, p);
475 buffer_put_string(&m, p, plen);
476 xfree(p);
477
478 plen = packet_get_keycontext(MODE_IN, NULL);
479 p = xmalloc(plen+1);
480 packet_get_keycontext(MODE_IN, p);
481 buffer_put_string(&m, p, plen);
482 xfree(p);
483
484 /* Compression state */
485 debug3("%s: Sending compression state", __FUNCTION__);
486 buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream));
487 buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream));
488
489 mm_request_send(socket, MONITOR_REQ_KEYEXPORT, &m);
490 debug3("%s: Finished sending state", __FUNCTION__);
491
492 buffer_free(&m);
493}
494
495int
496mm_pty_allocown(int socket, int *ptyfd, int *ttyfd,
497 char *namebuf, int namebuflen)
498{
499 Buffer m;
500 u_char *p;
501 int success = 0;
502
503 buffer_init(&m);
504 mm_request_send(socket, MONITOR_REQ_PTY, &m);
505
506 debug3("%s: waiting for MONITOR_ANS_PTY", __FUNCTION__);
507 mm_request_receive_expect(socket, MONITOR_ANS_PTY, &m);
508
509 success = buffer_get_int(&m);
510 if (success == 0) {
511 debug3("%s: pty alloc failed", __FUNCTION__);
512 buffer_free(&m);
513 return (0);
514 }
515 p = buffer_get_string(&m, NULL);
516 buffer_free(&m);
517
518 strlcpy(namebuf, p, namebuflen); /* Possible truncation */
519 xfree(p);
520
521 *ptyfd = mm_receive_fd(socket);
522 *ttyfd = mm_receive_fd(socket);
523
524 /* Success */
525 return (1);
526}
527
528/* Request process termination */
529
530void
531mm_terminate(int socket)
532{
533 Buffer m;
534
535 buffer_init(&m);
536 mm_request_send(socket, MONITOR_REQ_TERM, &m);
537 buffer_free(&m);
538}
diff --git a/monitor_wrap.h b/monitor_wrap.h
new file mode 100644
index 000000000..3c8378024
--- /dev/null
+++ b/monitor_wrap.h
@@ -0,0 +1,99 @@
1/*
2 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef _MM_WRAP_H_
27#define _MM_WRAP_H_
28#include "key.h"
29#include "buffer.h"
30
31struct mm_moduli {
32 int min;
33 int want;
34 int max;
35};
36
37enum mm_keytype {MM_HOSTKEY, MM_USERKEY};
38
39struct mm_keyallowed {
40 enum mm_keytype type;
41 char chost[MAXHOSTNAMELEN];
42 char cuser[MAXLOGNAME];
43};
44
45struct mm_master;
46
47struct passwd;
48DH *mm_choose_dh(int, int, int, int);
49DH *mm_read_moduli(int);
50int mm_key_sign(int, int, u_char **, u_int *, u_char *, u_int);
51void mm_inform_authserv(int, char *, char *);
52struct passwd *mm_getpwnamallow(int, const char *, int *);
53int mm_auth_password(int, char *);
54int mm_key_allowed(int, enum mm_keytype, char *, char *, Key *);
55#define mm_hostbased_key_allowed(x,u,h,z) \
56 mm_key_allowed(x, MM_HOSTKEY, u, h, z)
57#define mm_user_key_allowed(x,z) \
58 mm_key_allowed(x, MM_USERKEY, NULL, NULL, z)
59
60int mm_key_verify(int, enum mm_keytype, char *, char *,
61 Key *, u_char *, u_int, u_char *, u_int);
62
63void mm_terminate(int);
64
65/* Key export functions */
66struct Newkeys *mm_newkeys_from_blob(u_char *, int);
67int mm_newkeys_to_blob(int, u_char **, u_int *);
68
69void mm_apply_keystate(struct mm_master *);
70void mm_get_keystate(int);
71void mm_send_keystate(int);
72
73int mm_pty_allocown(int, int *, int *, char *, int);
74
75/* Functions on the montior that answer unprivileged requests */
76
77int mm_answer_moduli(int, Buffer *);
78int mm_answer_sign(int, Buffer *);
79int mm_answer_pwnamallow(int, Buffer *);
80int mm_answer_authserv(int, Buffer *);
81int mm_answer_authpassword(int, Buffer *);
82int mm_answer_keyallowed(int, Buffer *);
83int mm_answer_keyverify(int, Buffer *);
84int mm_answer_pty(int, Buffer *);
85int mm_answer_term(int, Buffer *);
86
87void mm_request_send(int , enum monitor_reqtype, Buffer *);
88void mm_request_receive(int, Buffer *);
89void mm_request_receive_expect(int, enum monitor_reqtype,
90 Buffer *);
91
92void *mm_zalloc(struct mm_master *, u_int, u_int);
93void mm_zfree(struct mm_master *, void *);
94void mm_init_compression(struct mm_master *);
95
96/* Utility functions */
97
98void pwfree(struct passwd *);
99#endif /* _MM_H_ */
diff --git a/packet.c b/packet.c
index 045d5a105..1c80af128 100644
--- a/packet.c
+++ b/packet.c
@@ -115,6 +115,8 @@ static int interactive_mode = 0;
115 115
116/* Session key information for Encryption and MAC */ 116/* Session key information for Encryption and MAC */
117Newkeys *newkeys[MODE_MAX]; 117Newkeys *newkeys[MODE_MAX];
118static u_int32_t read_seqnr = 0;
119static u_int32_t send_seqnr = 0;
118 120
119/* roundup current message to extra_pad bytes */ 121/* roundup current message to extra_pad bytes */
120static u_char extra_pad = 0; 122static u_char extra_pad = 0;
@@ -171,6 +173,87 @@ packet_connection_is_on_socket(void)
171 return 1; 173 return 1;
172} 174}
173 175
176/*
177 * Exports an IV from the CipherContext required to export the key
178 * state back from the unprivileged child to the privileged parent
179 * process.
180 */
181
182void
183packet_get_keyiv(int mode, u_char *iv, u_int len)
184{
185 CipherContext *cc;
186
187 if (mode == MODE_OUT)
188 cc = &send_context;
189 else
190 cc = &receive_context;
191
192 cipher_get_keyiv(cc, iv, len);
193}
194
195int
196packet_get_keycontext(int mode, u_char *dat)
197{
198 int plen;
199 CipherContext *cc;
200
201 if (mode == MODE_OUT)
202 cc = &send_context;
203 else
204 cc = &receive_context;
205
206#if OPENSSL_VERSION_NUMBER < 0x00907000L
207 plen = sizeof(cc->evp.c);
208#else
209 plen = cc->evp.cipher->ctx_size;
210#endif
211
212 if (dat == NULL)
213 return (plen);
214
215#if OPENSSL_VERSION_NUMBER < 0x00907000L
216 memcpy(dat, &cc->evp.c, sizeof(cc->evp.c));
217#else
218 memcpy(dat, &cc->evp.cipher_data, plen);
219#endif
220 return (plen);
221}
222
223void
224packet_set_keycontext(int mode, u_char *dat)
225{
226 CipherContext *cc;
227
228 if (mode == MODE_OUT)
229 cc = &send_context;
230 else
231 cc = &receive_context;
232
233#if OPENSSL_VERSION_NUMBER < 0x00907000L
234 memcpy(&cc->evp.c, dat, sizeof(cc->evp.c));
235#else
236 memcpy(&cc->evp.cipher_data, dat, cc->evp.cipher->ctx_size);
237#endif
238}
239
240u_int32_t
241packet_get_seqnr(int mode)
242{
243 return (mode == MODE_IN ? read_seqnr : send_seqnr);
244}
245
246void
247packet_set_seqnr(int mode, u_int32_t seqnr)
248{
249 if (mode == MODE_IN)
250 read_seqnr = seqnr;
251 else if (mode == MODE_OUT)
252 send_seqnr = seqnr;
253 else
254 fatal("%s: bad mode %d", __FUNCTION__, mode);
255}
256
174/* returns 1 if connection is via ipv4 */ 257/* returns 1 if connection is via ipv4 */
175 258
176int 259int
@@ -433,7 +516,7 @@ packet_send1(void)
433 */ 516 */
434} 517}
435 518
436static void 519void
437set_newkeys(int mode) 520set_newkeys(int mode)
438{ 521{
439 Enc *enc; 522 Enc *enc;
@@ -477,8 +560,9 @@ set_newkeys(int mode)
477 DBG(debug("cipher_init_context: %d", mode)); 560 DBG(debug("cipher_init_context: %d", mode));
478 cipher_init(cc, enc->cipher, enc->key, enc->key_len, 561 cipher_init(cc, enc->cipher, enc->key, enc->key_len,
479 enc->iv, enc->block_size, encrypt); 562 enc->iv, enc->block_size, encrypt);
480 memset(enc->iv, 0, enc->block_size); 563 /* Deleting the keys does not gain extra security */
481 memset(enc->key, 0, enc->key_len); 564 /* memset(enc->iv, 0, enc->block_size);
565 memset(enc->key, 0, enc->key_len); */
482 if (comp->type != 0 && comp->enabled == 0) { 566 if (comp->type != 0 && comp->enabled == 0) {
483 packet_init_compression(); 567 packet_init_compression();
484 if (mode == MODE_OUT) 568 if (mode == MODE_OUT)
@@ -495,7 +579,6 @@ set_newkeys(int mode)
495static void 579static void
496packet_send2(void) 580packet_send2(void)
497{ 581{
498 static u_int32_t seqnr = 0;
499 u_char type, *cp, *macbuf = NULL; 582 u_char type, *cp, *macbuf = NULL;
500 u_char padlen, pad; 583 u_char padlen, pad;
501 u_int packet_length = 0; 584 u_int packet_length = 0;
@@ -576,10 +659,10 @@ packet_send2(void)
576 659
577 /* compute MAC over seqnr and packet(length fields, payload, padding) */ 660 /* compute MAC over seqnr and packet(length fields, payload, padding) */
578 if (mac && mac->enabled) { 661 if (mac && mac->enabled) {
579 macbuf = mac_compute(mac, seqnr, 662 macbuf = mac_compute(mac, send_seqnr,
580 buffer_ptr(&outgoing_packet), 663 buffer_ptr(&outgoing_packet),
581 buffer_len(&outgoing_packet)); 664 buffer_len(&outgoing_packet));
582 DBG(debug("done calc MAC out #%d", seqnr)); 665 DBG(debug("done calc MAC out #%d", send_seqnr));
583 } 666 }
584 /* encrypt packet and append to output buffer. */ 667 /* encrypt packet and append to output buffer. */
585 cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); 668 cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
@@ -593,7 +676,7 @@ packet_send2(void)
593 buffer_dump(&output); 676 buffer_dump(&output);
594#endif 677#endif
595 /* increment sequence number for outgoing packets */ 678 /* increment sequence number for outgoing packets */
596 if (++seqnr == 0) 679 if (++send_seqnr == 0)
597 log("outgoing seqnr wraps around"); 680 log("outgoing seqnr wraps around");
598 buffer_clear(&outgoing_packet); 681 buffer_clear(&outgoing_packet);
599 682
@@ -783,7 +866,6 @@ packet_read_poll1(void)
783static int 866static int
784packet_read_poll2(u_int32_t *seqnr_p) 867packet_read_poll2(u_int32_t *seqnr_p)
785{ 868{
786 static u_int32_t seqnr = 0;
787 static u_int packet_length = 0; 869 static u_int packet_length = 0;
788 u_int padlen, need; 870 u_int padlen, need;
789 u_char *macbuf, *cp, type; 871 u_char *macbuf, *cp, type;
@@ -845,17 +927,17 @@ packet_read_poll2(u_int32_t *seqnr_p)
845 * increment sequence number for incoming packet 927 * increment sequence number for incoming packet
846 */ 928 */
847 if (mac && mac->enabled) { 929 if (mac && mac->enabled) {
848 macbuf = mac_compute(mac, seqnr, 930 macbuf = mac_compute(mac, read_seqnr,
849 buffer_ptr(&incoming_packet), 931 buffer_ptr(&incoming_packet),
850 buffer_len(&incoming_packet)); 932 buffer_len(&incoming_packet));
851 if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) 933 if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
852 packet_disconnect("Corrupted MAC on input."); 934 packet_disconnect("Corrupted MAC on input.");
853 DBG(debug("MAC #%d ok", seqnr)); 935 DBG(debug("MAC #%d ok", read_seqnr));
854 buffer_consume(&input, mac->mac_len); 936 buffer_consume(&input, mac->mac_len);
855 } 937 }
856 if (seqnr_p != NULL) 938 if (seqnr_p != NULL)
857 *seqnr_p = seqnr; 939 *seqnr_p = read_seqnr;
858 if (++seqnr == 0) 940 if (++read_seqnr == 0)
859 log("incoming seqnr wraps around"); 941 log("incoming seqnr wraps around");
860 942
861 /* get padlen */ 943 /* get padlen */
diff --git a/packet.h b/packet.h
index d6bf2aab4..b87a03cf8 100644
--- a/packet.h
+++ b/packet.h
@@ -56,6 +56,13 @@ void *packet_get_string(u_int *length_ptr);
56void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2))); 56void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
57void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); 57void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
58 58
59void set_newkeys(int mode);
60void packet_get_keyiv(int, u_char *, u_int);
61int packet_get_keycontext(int, u_char *);
62void packet_set_keycontext(int, u_char *);
63u_int32_t packet_get_seqnr(int);
64void packet_set_seqnr(int, u_int32_t);
65
59void packet_write_poll(void); 66void packet_write_poll(void);
60void packet_write_wait(void); 67void packet_write_wait(void);
61int packet_have_data_to_write(void); 68int packet_have_data_to_write(void);
diff --git a/servconf.c b/servconf.c
index 9bbd994ca..c3f1253e8 100644
--- a/servconf.c
+++ b/servconf.c
@@ -36,6 +36,8 @@ static void add_one_listen_addr(ServerOptions *, char *, u_short);
36 36
37/* AF_UNSPEC or AF_INET or AF_INET6 */ 37/* AF_UNSPEC or AF_INET or AF_INET6 */
38extern int IPv4or6; 38extern int IPv4or6;
39/* Use of privilege separation or not */
40extern int use_privsep;
39 41
40/* Initializes the server options to their default values. */ 42/* Initializes the server options to their default values. */
41 43
@@ -110,6 +112,9 @@ initialize_server_options(ServerOptions *options)
110 options->client_alive_count_max = -1; 112 options->client_alive_count_max = -1;
111 options->authorized_keys_file = NULL; 113 options->authorized_keys_file = NULL;
112 options->authorized_keys_file2 = NULL; 114 options->authorized_keys_file2 = NULL;
115
116 /* Needs to be accessable in many places */
117 use_privsep = -1;
113} 118}
114 119
115void 120void
@@ -235,6 +240,10 @@ fill_default_server_options(ServerOptions *options)
235 } 240 }
236 if (options->authorized_keys_file == NULL) 241 if (options->authorized_keys_file == NULL)
237 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; 242 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
243
244 /* Turn privilege separation on by default */
245 if (use_privsep == -1)
246 use_privsep = 1;
238} 247}
239 248
240/* Keyword tokens. */ 249/* Keyword tokens. */
@@ -267,6 +276,7 @@ typedef enum {
267 sBanner, sVerifyReverseMapping, sHostbasedAuthentication, 276 sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
268 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 277 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
269 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 278 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
279 sUsePrivilegeSeparation,
270 sDeprecated 280 sDeprecated
271} ServerOpCodes; 281} ServerOpCodes;
272 282
@@ -342,6 +352,7 @@ static struct {
342 { "clientalivecountmax", sClientAliveCountMax }, 352 { "clientalivecountmax", sClientAliveCountMax },
343 { "authorizedkeysfile", sAuthorizedKeysFile }, 353 { "authorizedkeysfile", sAuthorizedKeysFile },
344 { "authorizedkeysfile2", sAuthorizedKeysFile2 }, 354 { "authorizedkeysfile2", sAuthorizedKeysFile2 },
355 { "useprivilegeseparation", sUsePrivilegeSeparation},
345 { NULL, sBadOption } 356 { NULL, sBadOption }
346}; 357};
347 358
@@ -718,6 +729,10 @@ parse_flag:
718 intptr = &options->allow_tcp_forwarding; 729 intptr = &options->allow_tcp_forwarding;
719 goto parse_flag; 730 goto parse_flag;
720 731
732 case sUsePrivilegeSeparation:
733 intptr = &use_privsep;
734 goto parse_flag;
735
721 case sAllowUsers: 736 case sAllowUsers:
722 while ((arg = strdelim(&cp)) && *arg != '\0') { 737 while ((arg = strdelim(&cp)) && *arg != '\0') {
723 if (options->num_allow_users >= MAX_ALLOW_USERS) 738 if (options->num_allow_users >= MAX_ALLOW_USERS)
diff --git a/session.c b/session.c
index a31ff85d8..17227c9ff 100644
--- a/session.c
+++ b/session.c
@@ -56,6 +56,8 @@ RCSID("$OpenBSD: session.c,v 1.128 2002/02/16 00:51:44 markus Exp $");
56#include "serverloop.h" 56#include "serverloop.h"
57#include "canohost.h" 57#include "canohost.h"
58#include "session.h" 58#include "session.h"
59#include "monitor.h"
60#include "monitor_wrap.h"
59 61
60#ifdef HAVE_CYGWIN 62#ifdef HAVE_CYGWIN
61#include <windows.h> 63#include <windows.h>
@@ -63,39 +65,15 @@ RCSID("$OpenBSD: session.c,v 1.128 2002/02/16 00:51:44 markus Exp $");
63#define is_winnt (GetVersion() < 0x80000000) 65#define is_winnt (GetVersion() < 0x80000000)
64#endif 66#endif
65 67
66/* types */ 68/* Imports */
67 69extern int use_privsep;
68#define TTYSZ 64 70extern int mm_recvfd;
69typedef struct Session Session;
70struct Session {
71 int used;
72 int self;
73 struct passwd *pw;
74 Authctxt *authctxt;
75 pid_t pid;
76 /* tty */
77 char *term;
78 int ptyfd, ttyfd, ptymaster;
79 int row, col, xpixel, ypixel;
80 char tty[TTYSZ];
81 /* X11 */
82 int display_number;
83 char *display;
84 int screen;
85 char *auth_display;
86 char *auth_proto;
87 char *auth_data;
88 int single_connection;
89 /* proto 2 */
90 int chanid;
91 int is_subsystem;
92};
93 71
94/* func */ 72/* func */
95 73
96Session *session_new(void); 74Session *session_new(void);
97void session_set_fds(Session *, int, int, int); 75void session_set_fds(Session *, int, int, int);
98static void session_pty_cleanup(void *); 76void session_pty_cleanup(void *);
99void session_proctitle(Session *); 77void session_proctitle(Session *);
100int session_setup_x11fwd(Session *); 78int session_setup_x11fwd(Session *);
101void do_exec_pty(Session *, const char *); 79void do_exec_pty(Session *, const char *);
@@ -112,7 +90,6 @@ int check_quietlogin(Session *, const char *);
112static void do_authenticated1(Authctxt *); 90static void do_authenticated1(Authctxt *);
113static void do_authenticated2(Authctxt *); 91static void do_authenticated2(Authctxt *);
114 92
115static void session_close(Session *);
116static int session_pty_req(Session *); 93static int session_pty_req(Session *);
117 94
118/* import */ 95/* import */
@@ -1448,7 +1425,8 @@ session_pty_req(Session *s)
1448{ 1425{
1449 u_int len; 1426 u_int len;
1450 int n_bytes; 1427 int n_bytes;
1451 1428 int res;
1429
1452 if (no_pty_flag) { 1430 if (no_pty_flag) {
1453 debug("Allocating a pty not permitted for this authentication."); 1431 debug("Allocating a pty not permitted for this authentication.");
1454 return 0; 1432 return 0;
@@ -1477,7 +1455,15 @@ session_pty_req(Session *s)
1477 1455
1478 /* Allocate a pty and open it. */ 1456 /* Allocate a pty and open it. */
1479 debug("Allocating pty."); 1457 debug("Allocating pty.");
1480 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { 1458 if (!use_privsep) {
1459 res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
1460 sizeof(s->tty));
1461 if (res)
1462 pty_setowner(s->pw, s->tty);
1463 } else
1464 res = mm_pty_allocown(mm_recvfd,
1465 &s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
1466 if (!res) {
1481 if (s->term) 1467 if (s->term)
1482 xfree(s->term); 1468 xfree(s->term);
1483 s->term = NULL; 1469 s->term = NULL;
@@ -1498,7 +1484,6 @@ session_pty_req(Session *s)
1498 * time in case we call fatal() (e.g., the connection gets closed). 1484 * time in case we call fatal() (e.g., the connection gets closed).
1499 */ 1485 */
1500 fatal_add_cleanup(session_pty_cleanup, (void *)s); 1486 fatal_add_cleanup(session_pty_cleanup, (void *)s);
1501 pty_setowner(s->pw, s->tty);
1502 1487
1503 /* Set window size from the packet. */ 1488 /* Set window size from the packet. */
1504 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1489 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
@@ -1661,7 +1646,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
1661 * Function to perform pty cleanup. Also called if we get aborted abnormally 1646 * Function to perform pty cleanup. Also called if we get aborted abnormally
1662 * (e.g., due to a dropped connection). 1647 * (e.g., due to a dropped connection).
1663 */ 1648 */
1664static void 1649void
1665session_pty_cleanup(void *session) 1650session_pty_cleanup(void *session)
1666{ 1651{
1667 Session *s = session; 1652 Session *s = session;
@@ -1739,7 +1724,7 @@ session_exit_message(Session *s, int status)
1739 s->chanid = -1; 1724 s->chanid = -1;
1740} 1725}
1741 1726
1742static void 1727void
1743session_close(Session *s) 1728session_close(Session *s)
1744{ 1729{
1745 debug("session_close: session %d pid %d", s->self, s->pid); 1730 debug("session_close: session %d pid %d", s->self, s->pid);
diff --git a/session.h b/session.h
index ec8284a5f..e3123beed 100644
--- a/session.h
+++ b/session.h
@@ -26,6 +26,32 @@
26#ifndef SESSION_H 26#ifndef SESSION_H
27#define SESSION_H 27#define SESSION_H
28 28
29#define TTYSZ 64
30typedef struct Session Session;
31struct Session {
32 int used;
33 int self;
34 struct passwd *pw;
35 Authctxt *authctxt;
36 pid_t pid;
37 /* tty */
38 char *term;
39 int ptyfd, ttyfd, ptymaster;
40 int row, col, xpixel, ypixel;
41 char tty[TTYSZ];
42 /* X11 */
43 int display_number;
44 char *display;
45 int screen;
46 char *auth_display;
47 char *auth_proto;
48 char *auth_data;
49 int single_connection;
50 /* proto 2 */
51 int chanid;
52 int is_subsystem;
53};
54
29void do_authenticated(Authctxt *); 55void do_authenticated(Authctxt *);
30 56
31int session_open(Authctxt*, int); 57int session_open(Authctxt*, int);
@@ -34,4 +60,6 @@ void session_close_by_pid(pid_t, int);
34void session_close_by_channel(int, void *); 60void session_close_by_channel(int, void *);
35void session_destroy_all(void); 61void session_destroy_all(void);
36 62
63Session *session_new(void);
64void session_close(Session *);
37#endif 65#endif
diff --git a/sshd.c b/sshd.c
index ea9293251..cbe316087 100644
--- a/sshd.c
+++ b/sshd.c
@@ -72,6 +72,11 @@ RCSID("$OpenBSD: sshd.c,v 1.228 2002/02/27 21:23:13 stevesk Exp $");
72#include "misc.h" 72#include "misc.h"
73#include "dispatch.h" 73#include "dispatch.h"
74#include "channels.h" 74#include "channels.h"
75#include "session.h"
76#include "monitor_mm.h"
77#include "monitor.h"
78#include "monitor_wrap.h"
79#include "monitor_fdpass.h"
75 80
76#ifdef LIBWRAP 81#ifdef LIBWRAP
77#include <tcpd.h> 82#include <tcpd.h>
@@ -189,8 +194,20 @@ u_int utmp_len = MAXHOSTNAMELEN;
189int *startup_pipes = NULL; 194int *startup_pipes = NULL;
190int startup_pipe; /* in child */ 195int startup_pipe; /* in child */
191 196
197/* variables used for privilege separation */
198#define MM_MEMSIZE 65536
199struct mm_master *mm_zback;
200struct mm_master *mm_zlib;
201
202extern int use_privsep;
203/* Socket for the child to receive a fd */
204extern int mm_recvfd;
205/* Socket for the parent to send a fd */
206int mm_sendfd;
207
192/* Prototypes for various functions defined later in this file. */ 208/* Prototypes for various functions defined later in this file. */
193void destroy_sensitive_data(void); 209void destroy_sensitive_data(void);
210void demote_sensitive_data(void);
194 211
195static void do_ssh1_kex(void); 212static void do_ssh1_kex(void);
196static void do_ssh2_kex(void); 213static void do_ssh2_kex(void);
@@ -477,6 +494,69 @@ destroy_sensitive_data(void)
477 memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); 494 memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
478} 495}
479 496
497/* Demote private to public keys for network child */
498void
499demote_sensitive_data(void)
500{
501 Key *tmp;
502 int i;
503
504 if (sensitive_data.server_key) {
505 tmp = key_demote(sensitive_data.server_key);
506 key_free(sensitive_data.server_key);
507 sensitive_data.server_key = tmp;
508 }
509 for (i = 0; i < options.num_host_key_files; i++) {
510 if (sensitive_data.host_keys[i]) {
511 tmp = key_demote(sensitive_data.host_keys[i]);
512 key_free(sensitive_data.host_keys[i]);
513 sensitive_data.host_keys[i] = tmp;
514 }
515 }
516
517 /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */
518}
519
520void
521privsep_postauth(Authctxt *authctxt)
522{
523 pid_t pid;
524
525 if (0) {
526 /* File descriptor passing is broken */
527 mm_apply_keystate(mm_zlib);
528 use_privsep = 0;
529 return;
530 }
531
532 pid = fork();
533 if (pid == -1)
534 fatal("fork of unprivileged child failed");
535 else if (pid != 0) {
536 debug2("User child is on pid %d", pid);
537 close(mm_recvfd);
538 monitor_child_postauth(mm_sendfd);
539
540 /* Teardown? */
541 exit(0);
542 }
543
544 close(mm_sendfd);
545
546 /* Demote the private keys to public keys. */
547 demote_sensitive_data();
548
549 /* Drop privileges */
550 if (seteuid(authctxt->pw->pw_uid) == -1)
551 fatal("%s: seteuid", __FUNCTION__);
552 if (setuid(authctxt->pw->pw_uid) == -1)
553 fatal("%s: setuid", __FUNCTION__);
554
555 /* It is safe now to apply the key state */
556 mm_apply_keystate(mm_zlib);
557}
558
559
480static char * 560static char *
481list_hostkey_types(void) 561list_hostkey_types(void)
482{ 562{
@@ -518,6 +598,25 @@ get_hostkey_by_type(int type)
518 return NULL; 598 return NULL;
519} 599}
520 600
601Key *
602get_hostkey_by_index(int ind)
603{
604 if (ind < 0 || ind >= options.num_host_key_files)
605 return (NULL);
606 return (sensitive_data.host_keys[ind]);
607}
608
609int
610get_hostkey_index(Key *key)
611{
612 int i;
613 for (i = 0; i < options.num_host_key_files; i++) {
614 if (key == sensitive_data.host_keys[i])
615 return (i);
616 }
617 return (-1);
618}
619
521/* 620/*
522 * returns 1 if connection should be dropped, 0 otherwise. 621 * returns 1 if connection should be dropped, 0 otherwise.
523 * dropping starts at connection #max_startups_begin with a probability 622 * dropping starts at connection #max_startups_begin with a probability
@@ -594,6 +693,8 @@ main(int ac, char **av)
594 int listen_sock, maxfd; 693 int listen_sock, maxfd;
595 int startup_p[2]; 694 int startup_p[2];
596 int startups = 0; 695 int startups = 0;
696 Authctxt *authctxt;
697 int sp[2];
597 Key *key; 698 Key *key;
598 int ret, key_used = 0; 699 int ret, key_used = 0;
599 700
@@ -1231,23 +1332,84 @@ main(int ac, char **av)
1231 1332
1232 packet_set_nonblocking(); 1333 packet_set_nonblocking();
1233 1334
1335 if (!use_privsep)
1336 goto skip_privilegeseparation;
1337
1338 /* Set up unprivileged child process to deal with network data */
1339 monitor_socketpair(sp);
1340 mm_recvfd = sp[0];
1341 mm_sendfd = sp[1];
1342
1343 /* Used to share zlib space across processes */
1344 mm_zback = mm_create(NULL, MM_MEMSIZE);
1345 mm_zlib = mm_create(mm_zback, 20 * MM_MEMSIZE);
1346
1347 /* Compression needs to share state across borders */
1348 mm_init_compression(mm_zlib);
1349
1350 pid = fork();
1351 if (pid == -1)
1352 fatal("fork of unprivileged child failed");
1353 else if (pid != 0) {
1354 debug2("Network child is on pid %d", pid);
1355 authctxt = monitor_child_preauth(mm_sendfd);
1356
1357 /* The member allocation is not visible, so sync it */
1358 mm_share_sync(&mm_zlib, &mm_zback);
1359 goto authenticated;
1360 } else {
1361 /* Demote the private keys to public keys. */
1362 demote_sensitive_data();
1363
1364 /* Change our root directory - /var/empty is standard*/
1365 if (chroot("/var/empty") == -1)
1366 fatal("chroot(/var/empty)");
1367 if (chdir("/") == -1)
1368 fatal("chdir(/)");
1369
1370 /* Drop our privileges */
1371 seteuid(32767); /* XXX - Niels */
1372 setuid(32767);
1373 }
1374
1375 skip_privilegeseparation:
1376
1234 /* perform the key exchange */ 1377 /* perform the key exchange */
1235 /* authenticate user and start session */ 1378 /* authenticate user and start session */
1236 if (compat20) { 1379 if (compat20) {
1237 do_ssh2_kex(); 1380 do_ssh2_kex();
1238 do_authentication2(); 1381 authctxt = do_authentication2();
1382 if (use_privsep)
1383 mm_send_keystate(mm_recvfd);
1239 } else { 1384 } else {
1240 do_ssh1_kex(); 1385 do_ssh1_kex();
1241 do_authentication(); 1386 authctxt = do_authentication();
1242 } 1387 }
1243 /* The connection has been terminated. */ 1388
1244 verbose("Closing connection to %.100s", remote_ip); 1389 /* If we use privilege separation, the unprivileged child exits */
1390 if (use_privsep)
1391 exit(0);
1392
1393 authenticated:
1394 /*
1395 * In privilege separation, we fork another child and prepare
1396 * file descriptor passing.
1397 */
1398 if (use_privsep)
1399 privsep_postauth(authctxt);
1400
1401 /* Perform session preparation. */
1402 do_authenticated(authctxt);
1245 1403
1246#ifdef USE_PAM 1404#ifdef USE_PAM
1247 finish_pam(); 1405 finish_pam();
1248#endif /* USE_PAM */ 1406#endif /* USE_PAM */
1249 1407
1250 packet_close(); 1408 packet_close();
1409
1410 if (use_privsep)
1411 mm_terminate(mm_recvfd);
1412
1251 exit(0); 1413 exit(0);
1252} 1414}
1253 1415
@@ -1453,8 +1615,6 @@ do_ssh1_kex(void)
1453 for (i = 0; i < 16; i++) 1615 for (i = 0; i < 16; i++)
1454 session_id[i] = session_key[i] ^ session_key[i + 16]; 1616 session_id[i] = session_key[i] ^ session_key[i + 16];
1455 } 1617 }
1456 /* Destroy the private and public keys. They will no longer be needed. */
1457 destroy_sensitive_data();
1458 1618
1459 /* Destroy the decrypted integer. It is no longer needed. */ 1619 /* Destroy the decrypted integer. It is no longer needed. */
1460 BN_clear_free(session_key_int); 1620 BN_clear_free(session_key_int);
@@ -1502,6 +1662,7 @@ do_ssh2_kex(void)
1502 kex->client_version_string=client_version_string; 1662 kex->client_version_string=client_version_string;
1503 kex->server_version_string=server_version_string; 1663 kex->server_version_string=server_version_string;
1504 kex->load_host_key=&get_hostkey_by_type; 1664 kex->load_host_key=&get_hostkey_by_type;
1665 kex->host_key_index=&get_hostkey_index;
1505 1666
1506 xxx_kex = kex; 1667 xxx_kex = kex;
1507 1668