summaryrefslogtreecommitdiff
path: root/sshd.c
diff options
context:
space:
mode:
authorBen Lindstrom <mouring@eviladmin.org>2002-03-22 02:30:41 +0000
committerBen Lindstrom <mouring@eviladmin.org>2002-03-22 02:30:41 +0000
commit7a2073c50b92c053594d48a651ebafae052a71ed (patch)
tree7cfceb925262a07a356b0667e19f33eec497b602 /sshd.c
parent0f345f5ee1e71e1e9f8780ec13b2da23b6a9f7f8 (diff)
- provos@cvs.openbsd.org 2002/03/18 17:50:31
[auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c auth-skey.c auth.h auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c kexgex.c servconf.c session.h servconf.h serverloop.c session.c sshd.c] integrate privilege separated openssh; its turned off by default for now. work done by me and markus@ applied, but outside of ensure that smaller code bits migrated with their owners.. no work was tried to 'fix' it to work. =) Later project!
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c209
1 files changed, 203 insertions, 6 deletions
diff --git a/sshd.c b/sshd.c
index 0764588fc..c82603d58 100644
--- a/sshd.c
+++ b/sshd.c
@@ -15,8 +15,10 @@
15 * called by a name other than "ssh" or "Secure Shell". 15 * called by a name other than "ssh" or "Secure Shell".
16 * 16 *
17 * SSH2 implementation: 17 * SSH2 implementation:
18 * Privilege Separation:
18 * 19 *
19 * Copyright (c) 2000 Markus Friedl. All rights reserved. 20 * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
21 * Copyright (c) 2002 Niels Provos. All rights reserved.
20 * 22 *
21 * Redistribution and use in source and binary forms, with or without 23 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions 24 * modification, are permitted provided that the following conditions
@@ -40,11 +42,12 @@
40 */ 42 */
41 43
42#include "includes.h" 44#include "includes.h"
43RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $"); 45RCSID("$OpenBSD: sshd.c,v 1.231 2002/03/18 17:50:31 provos Exp $");
44 46
45#include <openssl/dh.h> 47#include <openssl/dh.h>
46#include <openssl/bn.h> 48#include <openssl/bn.h>
47#include <openssl/md5.h> 49#include <openssl/md5.h>
50#include <openssl/rand.h>
48 51
49#include "ssh.h" 52#include "ssh.h"
50#include "ssh1.h" 53#include "ssh1.h"
@@ -73,6 +76,10 @@ RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $");
73#include "dispatch.h" 76#include "dispatch.h"
74#include "channels.h" 77#include "channels.h"
75#include "session.h" 78#include "session.h"
79#include "monitor_mm.h"
80#include "monitor.h"
81#include "monitor_wrap.h"
82#include "monitor_fdpass.h"
76 83
77#ifdef LIBWRAP 84#ifdef LIBWRAP
78#include <tcpd.h> 85#include <tcpd.h>
@@ -190,8 +197,13 @@ u_int utmp_len = MAXHOSTNAMELEN;
190int *startup_pipes = NULL; 197int *startup_pipes = NULL;
191int startup_pipe; /* in child */ 198int startup_pipe; /* in child */
192 199
200/* variables used for privilege separation */
201extern struct monitor *monitor;
202extern int use_privsep;
203
193/* Prototypes for various functions defined later in this file. */ 204/* Prototypes for various functions defined later in this file. */
194void destroy_sensitive_data(void); 205void destroy_sensitive_data(void);
206void demote_sensitive_data(void);
195 207
196static void do_ssh1_kex(void); 208static void do_ssh1_kex(void);
197static void do_ssh2_kex(void); 209static void do_ssh2_kex(void);
@@ -478,6 +490,115 @@ destroy_sensitive_data(void)
478 memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); 490 memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
479} 491}
480 492
493/* Demote private to public keys for network child */
494void
495demote_sensitive_data(void)
496{
497 Key *tmp;
498 int i;
499
500 if (sensitive_data.server_key) {
501 tmp = key_demote(sensitive_data.server_key);
502 key_free(sensitive_data.server_key);
503 sensitive_data.server_key = tmp;
504 }
505
506 for (i = 0; i < options.num_host_key_files; i++) {
507 if (sensitive_data.host_keys[i]) {
508 tmp = key_demote(sensitive_data.host_keys[i]);
509 key_free(sensitive_data.host_keys[i]);
510 sensitive_data.host_keys[i] = tmp;
511 if (tmp->type == KEY_RSA1)
512 sensitive_data.ssh1_host_key = tmp;
513 }
514 }
515
516 /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */
517}
518
519void
520privsep_preauth_child(void)
521{
522 u_int32_t rand[256];
523 int i;
524
525 /* Enable challenge-response authentication for privilege separation */
526 privsep_challenge_enable();
527
528 for (i = 0; i < 256; i++)
529 rand[i] = arc4random();
530 RAND_seed(rand, sizeof(rand));
531
532 /* Demote the private keys to public keys. */
533 demote_sensitive_data();
534
535 /* Change our root directory*/
536 if (chroot(options.unprivileged_dir) == -1)
537 fatal("chroot(/var/empty)");
538 if (chdir("/") == -1)
539 fatal("chdir(/)");
540
541 /* Drop our privileges */
542 setegid(options.unprivileged_group);
543 setgid(options.unprivileged_group);
544 seteuid(options.unprivileged_user);
545 setuid(options.unprivileged_user);
546}
547
548void
549privsep_postauth(Authctxt *authctxt, pid_t pid)
550{
551 extern Authctxt *x_authctxt;
552 int status;
553
554 /* Wait for the child's exit status */
555 waitpid(pid, &status, 0);
556
557 /* XXX - Remote port forwarding */
558 x_authctxt = authctxt;
559
560 if (authctxt->pw->pw_uid == 0 || options.use_login) {
561 /* File descriptor passing is broken or root login */
562 monitor_apply_keystate(monitor);
563 use_privsep = 0;
564 return;
565 }
566
567 /* Authentication complete */
568 alarm(0);
569 if (startup_pipe != -1) {
570 close(startup_pipe);
571 startup_pipe = -1;
572 }
573
574 /* New socket pair */
575 monitor_reinit(monitor);
576
577 monitor->m_pid = fork();
578 if (monitor->m_pid == -1)
579 fatal("fork of unprivileged child failed");
580 else if (monitor->m_pid != 0) {
581 debug2("User child is on pid %d", pid);
582 close(monitor->m_recvfd);
583 monitor_child_postauth(monitor);
584
585 /* NEVERREACHED */
586 exit(0);
587 }
588
589 close(monitor->m_sendfd);
590
591 /* Demote the private keys to public keys. */
592 demote_sensitive_data();
593
594 /* Drop privileges */
595 do_setusercontext(authctxt->pw);
596
597 /* It is safe now to apply the key state */
598 monitor_apply_keystate(monitor);
599}
600
601
481static char * 602static char *
482list_hostkey_types(void) 603list_hostkey_types(void)
483{ 604{
@@ -507,7 +628,7 @@ list_hostkey_types(void)
507 return p; 628 return p;
508} 629}
509 630
510static Key * 631Key *
511get_hostkey_by_type(int type) 632get_hostkey_by_type(int type)
512{ 633{
513 int i; 634 int i;
@@ -519,6 +640,25 @@ get_hostkey_by_type(int type)
519 return NULL; 640 return NULL;
520} 641}
521 642
643Key *
644get_hostkey_by_index(int ind)
645{
646 if (ind < 0 || ind >= options.num_host_key_files)
647 return (NULL);
648 return (sensitive_data.host_keys[ind]);
649}
650
651int
652get_hostkey_index(Key *key)
653{
654 int i;
655 for (i = 0; i < options.num_host_key_files; i++) {
656 if (key == sensitive_data.host_keys[i])
657 return (i);
658 }
659 return (-1);
660}
661
522/* 662/*
523 * returns 1 if connection should be dropped, 0 otherwise. 663 * returns 1 if connection should be dropped, 0 otherwise.
524 * dropping starts at connection #max_startups_begin with a probability 664 * dropping starts at connection #max_startups_begin with a probability
@@ -1233,6 +1373,37 @@ main(int ac, char **av)
1233 1373
1234 packet_set_nonblocking(); 1374 packet_set_nonblocking();
1235 1375
1376 if (!use_privsep)
1377 goto skip_privilegeseparation;
1378
1379 /* Set up unprivileged child process to deal with network data */
1380 monitor = monitor_init();
1381 /* Store a pointer to the kex for later rekeying */
1382 monitor->m_pkex = &xxx_kex;
1383
1384 pid = fork();
1385 if (pid == -1)
1386 fatal("fork of unprivileged child failed");
1387 else if (pid != 0) {
1388 debug2("Network child is on pid %d", pid);
1389
1390 close(monitor->m_recvfd);
1391 authctxt = monitor_child_preauth(monitor);
1392 close(monitor->m_sendfd);
1393
1394 /* Sync memory */
1395 monitor_sync(monitor);
1396 goto authenticated;
1397 } else {
1398 close(monitor->m_sendfd);
1399
1400 /* Demote the child */
1401 if (getuid() == 0 || geteuid() == 0)
1402 privsep_preauth_child();
1403 }
1404
1405 skip_privilegeseparation:
1406
1236 /* perform the key exchange */ 1407 /* perform the key exchange */
1237 /* authenticate user and start session */ 1408 /* authenticate user and start session */
1238 if (compat20) { 1409 if (compat20) {
@@ -1242,6 +1413,23 @@ main(int ac, char **av)
1242 do_ssh1_kex(); 1413 do_ssh1_kex();
1243 authctxt = do_authentication(); 1414 authctxt = do_authentication();
1244 } 1415 }
1416 if (use_privsep)
1417 mm_send_keystate(monitor);
1418
1419 /* If we use privilege separation, the unprivileged child exits */
1420 if (use_privsep)
1421 exit(0);
1422
1423 authenticated:
1424 /*
1425 * In privilege separation, we fork another child and prepare
1426 * file descriptor passing.
1427 */
1428 if (use_privsep) {
1429 privsep_postauth(authctxt, pid);
1430 if (!compat20)
1431 destroy_sensitive_data();
1432 }
1245 1433
1246 /* Perform session preparation. */ 1434 /* Perform session preparation. */
1247 do_authenticated(authctxt); 1435 do_authenticated(authctxt);
@@ -1254,6 +1442,10 @@ main(int ac, char **av)
1254#endif /* USE_PAM */ 1442#endif /* USE_PAM */
1255 1443
1256 packet_close(); 1444 packet_close();
1445
1446 if (use_privsep)
1447 mm_terminate();
1448
1257 exit(0); 1449 exit(0);
1258} 1450}
1259 1451
@@ -1261,7 +1453,7 @@ main(int ac, char **av)
1261 * Decrypt session_key_int using our private server key and private host key 1453 * Decrypt session_key_int using our private server key and private host key
1262 * (key with larger modulus first). 1454 * (key with larger modulus first).
1263 */ 1455 */
1264static int 1456int
1265ssh1_session_key(BIGNUM *session_key_int) 1457ssh1_session_key(BIGNUM *session_key_int)
1266{ 1458{
1267 int rsafail = 0; 1459 int rsafail = 0;
@@ -1417,7 +1609,8 @@ do_ssh1_kex(void)
1417 packet_check_eom(); 1609 packet_check_eom();
1418 1610
1419 /* Decrypt session_key_int using host/server keys */ 1611 /* Decrypt session_key_int using host/server keys */
1420 rsafail = ssh1_session_key(session_key_int); 1612 rsafail = PRIVSEP(ssh1_session_key(session_key_int));
1613
1421 /* 1614 /*
1422 * Extract session key from the decrypted integer. The key is in the 1615 * Extract session key from the decrypted integer. The key is in the
1423 * least significant 256 bits of the integer; the first byte of the 1616 * least significant 256 bits of the integer; the first byte of the
@@ -1468,9 +1661,12 @@ do_ssh1_kex(void)
1468 for (i = 0; i < 16; i++) 1661 for (i = 0; i < 16; i++)
1469 session_id[i] = session_key[i] ^ session_key[i + 16]; 1662 session_id[i] = session_key[i] ^ session_key[i + 16];
1470 } 1663 }
1471 /* Destroy the private and public keys. They will no longer be needed. */ 1664 /* Destroy the private and public keys. No longer. */
1472 destroy_sensitive_data(); 1665 destroy_sensitive_data();
1473 1666
1667 if (use_privsep)
1668 mm_ssh1_session_id(session_id);
1669
1474 /* Destroy the decrypted integer. It is no longer needed. */ 1670 /* Destroy the decrypted integer. It is no longer needed. */
1475 BN_clear_free(session_key_int); 1671 BN_clear_free(session_key_int);
1476 1672
@@ -1517,6 +1713,7 @@ do_ssh2_kex(void)
1517 kex->client_version_string=client_version_string; 1713 kex->client_version_string=client_version_string;
1518 kex->server_version_string=server_version_string; 1714 kex->server_version_string=server_version_string;
1519 kex->load_host_key=&get_hostkey_by_type; 1715 kex->load_host_key=&get_hostkey_by_type;
1716 kex->host_key_index=&get_hostkey_index;
1520 1717
1521 xxx_kex = kex; 1718 xxx_kex = kex;
1522 1719