diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 173 |
1 files changed, 167 insertions, 6 deletions
@@ -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; | |||
189 | int *startup_pipes = NULL; | 194 | int *startup_pipes = NULL; |
190 | int startup_pipe; /* in child */ | 195 | int startup_pipe; /* in child */ |
191 | 196 | ||
197 | /* variables used for privilege separation */ | ||
198 | #define MM_MEMSIZE 65536 | ||
199 | struct mm_master *mm_zback; | ||
200 | struct mm_master *mm_zlib; | ||
201 | |||
202 | extern int use_privsep; | ||
203 | /* Socket for the child to receive a fd */ | ||
204 | extern int mm_recvfd; | ||
205 | /* Socket for the parent to send a fd */ | ||
206 | int mm_sendfd; | ||
207 | |||
192 | /* Prototypes for various functions defined later in this file. */ | 208 | /* Prototypes for various functions defined later in this file. */ |
193 | void destroy_sensitive_data(void); | 209 | void destroy_sensitive_data(void); |
210 | void demote_sensitive_data(void); | ||
194 | 211 | ||
195 | static void do_ssh1_kex(void); | 212 | static void do_ssh1_kex(void); |
196 | static void do_ssh2_kex(void); | 213 | static 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 */ | ||
498 | void | ||
499 | demote_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 | |||
520 | void | ||
521 | privsep_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 | |||
480 | static char * | 560 | static char * |
481 | list_hostkey_types(void) | 561 | list_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 | ||
601 | Key * | ||
602 | get_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 | |||
609 | int | ||
610 | get_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 | ||