diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 108 |
1 files changed, 64 insertions, 44 deletions
@@ -42,7 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include "includes.h" | 44 | #include "includes.h" |
45 | RCSID("$OpenBSD: sshd.c,v 1.276 2003/08/28 12:54:34 markus Exp $"); | 45 | RCSID("$OpenBSD: sshd.c,v 1.286 2004/02/23 12:02:33 markus Exp $"); |
46 | 46 | ||
47 | #include <openssl/dh.h> | 47 | #include <openssl/dh.h> |
48 | #include <openssl/bn.h> | 48 | #include <openssl/bn.h> |
@@ -101,6 +101,7 @@ extern char *__progname; | |||
101 | #else | 101 | #else |
102 | char *__progname; | 102 | char *__progname; |
103 | #endif | 103 | #endif |
104 | extern char **environ; | ||
104 | 105 | ||
105 | /* Server configuration options. */ | 106 | /* Server configuration options. */ |
106 | ServerOptions options; | 107 | ServerOptions options; |
@@ -199,11 +200,14 @@ int startup_pipe; /* in child */ | |||
199 | 200 | ||
200 | /* variables used for privilege separation */ | 201 | /* variables used for privilege separation */ |
201 | int use_privsep; | 202 | int use_privsep; |
202 | struct monitor *pmonitor; | 203 | struct monitor *pmonitor = NULL; |
203 | 204 | ||
204 | /* message to be displayed after login */ | 205 | /* message to be displayed after login */ |
205 | Buffer loginmsg; | 206 | Buffer loginmsg; |
206 | 207 | ||
208 | /* global authentication context */ | ||
209 | Authctxt *the_authctxt = NULL; | ||
210 | |||
207 | /* Prototypes for various functions defined later in this file. */ | 211 | /* Prototypes for various functions defined later in this file. */ |
208 | void destroy_sensitive_data(void); | 212 | void destroy_sensitive_data(void); |
209 | void demote_sensitive_data(void); | 213 | void demote_sensitive_data(void); |
@@ -302,6 +306,9 @@ grace_alarm_handler(int sig) | |||
302 | { | 306 | { |
303 | /* XXX no idea how fix this signal handler */ | 307 | /* XXX no idea how fix this signal handler */ |
304 | 308 | ||
309 | if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) | ||
310 | kill(pmonitor->m_pid, SIGALRM); | ||
311 | |||
305 | /* Log error and exit. */ | 312 | /* Log error and exit. */ |
306 | fatal("Timeout before authentication for %s", get_remote_ipaddr()); | 313 | fatal("Timeout before authentication for %s", get_remote_ipaddr()); |
307 | } | 314 | } |
@@ -375,7 +382,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
375 | strlen(server_version_string)) | 382 | strlen(server_version_string)) |
376 | != strlen(server_version_string)) { | 383 | != strlen(server_version_string)) { |
377 | logit("Could not write ident string to %s", get_remote_ipaddr()); | 384 | logit("Could not write ident string to %s", get_remote_ipaddr()); |
378 | fatal_cleanup(); | 385 | cleanup_exit(255); |
379 | } | 386 | } |
380 | 387 | ||
381 | /* Read other sides version identification. */ | 388 | /* Read other sides version identification. */ |
@@ -384,7 +391,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
384 | if (atomicio(read, sock_in, &buf[i], 1) != 1) { | 391 | if (atomicio(read, sock_in, &buf[i], 1) != 1) { |
385 | logit("Did not receive identification string from %s", | 392 | logit("Did not receive identification string from %s", |
386 | get_remote_ipaddr()); | 393 | get_remote_ipaddr()); |
387 | fatal_cleanup(); | 394 | cleanup_exit(255); |
388 | } | 395 | } |
389 | if (buf[i] == '\r') { | 396 | if (buf[i] == '\r') { |
390 | buf[i] = 0; | 397 | buf[i] = 0; |
@@ -414,7 +421,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
414 | close(sock_out); | 421 | close(sock_out); |
415 | logit("Bad protocol version identification '%.100s' from %s", | 422 | logit("Bad protocol version identification '%.100s' from %s", |
416 | client_version_string, get_remote_ipaddr()); | 423 | client_version_string, get_remote_ipaddr()); |
417 | fatal_cleanup(); | 424 | cleanup_exit(255); |
418 | } | 425 | } |
419 | debug("Client protocol version %d.%d; client software version %.100s", | 426 | debug("Client protocol version %d.%d; client software version %.100s", |
420 | remote_major, remote_minor, remote_version); | 427 | remote_major, remote_minor, remote_version); |
@@ -424,13 +431,13 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
424 | if (datafellows & SSH_BUG_PROBE) { | 431 | if (datafellows & SSH_BUG_PROBE) { |
425 | logit("probed from %s with %s. Don't panic.", | 432 | logit("probed from %s with %s. Don't panic.", |
426 | get_remote_ipaddr(), client_version_string); | 433 | get_remote_ipaddr(), client_version_string); |
427 | fatal_cleanup(); | 434 | cleanup_exit(255); |
428 | } | 435 | } |
429 | 436 | ||
430 | if (datafellows & SSH_BUG_SCANNER) { | 437 | if (datafellows & SSH_BUG_SCANNER) { |
431 | logit("scanned from %s with %s. Don't panic.", | 438 | logit("scanned from %s with %s. Don't panic.", |
432 | get_remote_ipaddr(), client_version_string); | 439 | get_remote_ipaddr(), client_version_string); |
433 | fatal_cleanup(); | 440 | cleanup_exit(255); |
434 | } | 441 | } |
435 | 442 | ||
436 | mismatch = 0; | 443 | mismatch = 0; |
@@ -476,7 +483,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
476 | logit("Protocol major versions differ for %s: %.200s vs. %.200s", | 483 | logit("Protocol major versions differ for %s: %.200s vs. %.200s", |
477 | get_remote_ipaddr(), | 484 | get_remote_ipaddr(), |
478 | server_version_string, client_version_string); | 485 | server_version_string, client_version_string); |
479 | fatal_cleanup(); | 486 | cleanup_exit(255); |
480 | } | 487 | } |
481 | } | 488 | } |
482 | 489 | ||
@@ -571,10 +578,9 @@ privsep_preauth_child(void) | |||
571 | #endif | 578 | #endif |
572 | } | 579 | } |
573 | 580 | ||
574 | static Authctxt * | 581 | static int |
575 | privsep_preauth(void) | 582 | privsep_preauth(Authctxt *authctxt) |
576 | { | 583 | { |
577 | Authctxt *authctxt = NULL; | ||
578 | int status; | 584 | int status; |
579 | pid_t pid; | 585 | pid_t pid; |
580 | 586 | ||
@@ -587,12 +593,11 @@ privsep_preauth(void) | |||
587 | if (pid == -1) { | 593 | if (pid == -1) { |
588 | fatal("fork of unprivileged child failed"); | 594 | fatal("fork of unprivileged child failed"); |
589 | } else if (pid != 0) { | 595 | } else if (pid != 0) { |
590 | fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); | ||
591 | |||
592 | debug2("Network child is on pid %ld", (long)pid); | 596 | debug2("Network child is on pid %ld", (long)pid); |
593 | 597 | ||
594 | close(pmonitor->m_recvfd); | 598 | close(pmonitor->m_recvfd); |
595 | authctxt = monitor_child_preauth(pmonitor); | 599 | pmonitor->m_pid = pid; |
600 | monitor_child_preauth(authctxt, pmonitor); | ||
596 | close(pmonitor->m_sendfd); | 601 | close(pmonitor->m_sendfd); |
597 | 602 | ||
598 | /* Sync memory */ | 603 | /* Sync memory */ |
@@ -602,11 +607,7 @@ privsep_preauth(void) | |||
602 | while (waitpid(pid, &status, 0) < 0) | 607 | while (waitpid(pid, &status, 0) < 0) |
603 | if (errno != EINTR) | 608 | if (errno != EINTR) |
604 | break; | 609 | break; |
605 | 610 | return (1); | |
606 | /* Reinstall, since the child has finished */ | ||
607 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); | ||
608 | |||
609 | return (authctxt); | ||
610 | } else { | 611 | } else { |
611 | /* child */ | 612 | /* child */ |
612 | 613 | ||
@@ -617,17 +618,12 @@ privsep_preauth(void) | |||
617 | privsep_preauth_child(); | 618 | privsep_preauth_child(); |
618 | setproctitle("%s", "[net]"); | 619 | setproctitle("%s", "[net]"); |
619 | } | 620 | } |
620 | return (NULL); | 621 | return (0); |
621 | } | 622 | } |
622 | 623 | ||
623 | static void | 624 | static void |
624 | privsep_postauth(Authctxt *authctxt) | 625 | privsep_postauth(Authctxt *authctxt) |
625 | { | 626 | { |
626 | extern Authctxt *x_authctxt; | ||
627 | |||
628 | /* XXX - Remote port forwarding */ | ||
629 | x_authctxt = authctxt; | ||
630 | |||
631 | #ifdef DISABLE_FD_PASSING | 627 | #ifdef DISABLE_FD_PASSING |
632 | if (1) { | 628 | if (1) { |
633 | #else | 629 | #else |
@@ -653,8 +649,6 @@ privsep_postauth(Authctxt *authctxt) | |||
653 | if (pmonitor->m_pid == -1) | 649 | if (pmonitor->m_pid == -1) |
654 | fatal("fork of unprivileged child failed"); | 650 | fatal("fork of unprivileged child failed"); |
655 | else if (pmonitor->m_pid != 0) { | 651 | else if (pmonitor->m_pid != 0) { |
656 | fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); | ||
657 | |||
658 | debug2("User child is on pid %ld", (long)pmonitor->m_pid); | 652 | debug2("User child is on pid %ld", (long)pmonitor->m_pid); |
659 | close(pmonitor->m_recvfd); | 653 | close(pmonitor->m_recvfd); |
660 | monitor_child_postauth(pmonitor); | 654 | monitor_child_postauth(pmonitor); |
@@ -679,7 +673,8 @@ static char * | |||
679 | list_hostkey_types(void) | 673 | list_hostkey_types(void) |
680 | { | 674 | { |
681 | Buffer b; | 675 | Buffer b; |
682 | char *p; | 676 | const char *p; |
677 | char *ret; | ||
683 | int i; | 678 | int i; |
684 | 679 | ||
685 | buffer_init(&b); | 680 | buffer_init(&b); |
@@ -698,10 +693,10 @@ list_hostkey_types(void) | |||
698 | } | 693 | } |
699 | } | 694 | } |
700 | buffer_append(&b, "\0", 1); | 695 | buffer_append(&b, "\0", 1); |
701 | p = xstrdup(buffer_ptr(&b)); | 696 | ret = xstrdup(buffer_ptr(&b)); |
702 | buffer_free(&b); | 697 | buffer_free(&b); |
703 | debug("list_hostkey_types: %s", p); | 698 | debug("list_hostkey_types: %s", ret); |
704 | return p; | 699 | return ret; |
705 | } | 700 | } |
706 | 701 | ||
707 | Key * | 702 | Key * |
@@ -769,7 +764,8 @@ drop_connection(int startups) | |||
769 | static void | 764 | static void |
770 | usage(void) | 765 | usage(void) |
771 | { | 766 | { |
772 | fprintf(stderr, "sshd version %s\n", SSH_VERSION); | 767 | fprintf(stderr, "sshd version %s, %s\n", |
768 | SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); | ||
773 | fprintf(stderr, "Usage: %s [options]\n", __progname); | 769 | fprintf(stderr, "Usage: %s [options]\n", __progname); |
774 | fprintf(stderr, "Options:\n"); | 770 | fprintf(stderr, "Options:\n"); |
775 | fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); | 771 | fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); |
@@ -809,11 +805,12 @@ main(int ac, char **av) | |||
809 | FILE *f; | 805 | FILE *f; |
810 | struct addrinfo *ai; | 806 | struct addrinfo *ai; |
811 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 807 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
808 | char *line; | ||
812 | int listen_sock, maxfd; | 809 | int listen_sock, maxfd; |
813 | int startup_p[2]; | 810 | int startup_p[2]; |
814 | int startups = 0; | 811 | int startups = 0; |
815 | Authctxt *authctxt; | ||
816 | Key *key; | 812 | Key *key; |
813 | Authctxt *authctxt; | ||
817 | int ret, key_used = 0; | 814 | int ret, key_used = 0; |
818 | 815 | ||
819 | #ifdef HAVE_SECUREWARE | 816 | #ifdef HAVE_SECUREWARE |
@@ -922,9 +919,11 @@ main(int ac, char **av) | |||
922 | } | 919 | } |
923 | break; | 920 | break; |
924 | case 'o': | 921 | case 'o': |
925 | if (process_server_config_line(&options, optarg, | 922 | line = xstrdup(optarg); |
923 | if (process_server_config_line(&options, line, | ||
926 | "command-line", 0) != 0) | 924 | "command-line", 0) != 0) |
927 | exit(1); | 925 | exit(1); |
926 | xfree(line); | ||
928 | break; | 927 | break; |
929 | case '?': | 928 | case '?': |
930 | default: | 929 | default: |
@@ -1069,8 +1068,8 @@ main(int ac, char **av) | |||
1069 | /* | 1068 | /* |
1070 | * Clear out any supplemental groups we may have inherited. This | 1069 | * Clear out any supplemental groups we may have inherited. This |
1071 | * prevents inadvertent creation of files with bad modes (in the | 1070 | * prevents inadvertent creation of files with bad modes (in the |
1072 | * portable version at least, it's certainly possible for PAM | 1071 | * portable version at least, it's certainly possible for PAM |
1073 | * to create a file, and we can't control the code in every | 1072 | * to create a file, and we can't control the code in every |
1074 | * module which might be used). | 1073 | * module which might be used). |
1075 | */ | 1074 | */ |
1076 | if (setgroups(0, NULL) < 0) | 1075 | if (setgroups(0, NULL) < 0) |
@@ -1112,6 +1111,11 @@ main(int ac, char **av) | |||
1112 | unmounted if desired. */ | 1111 | unmounted if desired. */ |
1113 | chdir("/"); | 1112 | chdir("/"); |
1114 | 1113 | ||
1114 | #ifndef HAVE_CYGWIN | ||
1115 | /* Clear environment */ | ||
1116 | environ[0] = NULL; | ||
1117 | #endif | ||
1118 | |||
1115 | /* ignore SIGPIPE */ | 1119 | /* ignore SIGPIPE */ |
1116 | signal(SIGPIPE, SIG_IGN); | 1120 | signal(SIGPIPE, SIG_IGN); |
1117 | 1121 | ||
@@ -1180,7 +1184,7 @@ main(int ac, char **av) | |||
1180 | 1184 | ||
1181 | /* Start listening on the port. */ | 1185 | /* Start listening on the port. */ |
1182 | logit("Server listening on %s port %s.", ntop, strport); | 1186 | logit("Server listening on %s port %s.", ntop, strport); |
1183 | if (listen(listen_sock, 5) < 0) | 1187 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) |
1184 | fatal("listen: %.100s", strerror(errno)); | 1188 | fatal("listen: %.100s", strerror(errno)); |
1185 | 1189 | ||
1186 | } | 1190 | } |
@@ -1419,8 +1423,8 @@ main(int ac, char **av) | |||
1419 | signal(SIGCHLD, SIG_DFL); | 1423 | signal(SIGCHLD, SIG_DFL); |
1420 | signal(SIGINT, SIG_DFL); | 1424 | signal(SIGINT, SIG_DFL); |
1421 | 1425 | ||
1422 | /* Set keepalives if requested. */ | 1426 | /* Set SO_KEEPALIVE if requested. */ |
1423 | if (options.keepalives && | 1427 | if (options.tcp_keep_alive && |
1424 | setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, | 1428 | setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, |
1425 | sizeof(on)) < 0) | 1429 | sizeof(on)) < 0) |
1426 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | 1430 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
@@ -1470,21 +1474,28 @@ main(int ac, char **av) | |||
1470 | 1474 | ||
1471 | packet_set_nonblocking(); | 1475 | packet_set_nonblocking(); |
1472 | 1476 | ||
1473 | /* prepare buffers to collect authentication messages */ | 1477 | /* prepare buffers to collect authentication messages */ |
1474 | buffer_init(&loginmsg); | 1478 | buffer_init(&loginmsg); |
1475 | 1479 | ||
1480 | /* allocate authentication context */ | ||
1481 | authctxt = xmalloc(sizeof(*authctxt)); | ||
1482 | memset(authctxt, 0, sizeof(*authctxt)); | ||
1483 | |||
1484 | /* XXX global for cleanup, access from other modules */ | ||
1485 | the_authctxt = authctxt; | ||
1486 | |||
1476 | if (use_privsep) | 1487 | if (use_privsep) |
1477 | if ((authctxt = privsep_preauth()) != NULL) | 1488 | if (privsep_preauth(authctxt) == 1) |
1478 | goto authenticated; | 1489 | goto authenticated; |
1479 | 1490 | ||
1480 | /* perform the key exchange */ | 1491 | /* perform the key exchange */ |
1481 | /* authenticate user and start session */ | 1492 | /* authenticate user and start session */ |
1482 | if (compat20) { | 1493 | if (compat20) { |
1483 | do_ssh2_kex(); | 1494 | do_ssh2_kex(); |
1484 | authctxt = do_authentication2(); | 1495 | do_authentication2(authctxt); |
1485 | } else { | 1496 | } else { |
1486 | do_ssh1_kex(); | 1497 | do_ssh1_kex(); |
1487 | authctxt = do_authentication(); | 1498 | do_authentication(authctxt); |
1488 | } | 1499 | } |
1489 | /* | 1500 | /* |
1490 | * If we use privilege separation, the unprivileged child transfers | 1501 | * If we use privilege separation, the unprivileged child transfers |
@@ -1507,7 +1518,7 @@ main(int ac, char **av) | |||
1507 | destroy_sensitive_data(); | 1518 | destroy_sensitive_data(); |
1508 | } | 1519 | } |
1509 | 1520 | ||
1510 | /* Perform session preparation. */ | 1521 | /* Start session. */ |
1511 | do_authenticated(authctxt); | 1522 | do_authenticated(authctxt); |
1512 | 1523 | ||
1513 | /* The connection has been terminated. */ | 1524 | /* The connection has been terminated. */ |
@@ -1800,3 +1811,12 @@ do_ssh2_kex(void) | |||
1800 | #endif | 1811 | #endif |
1801 | debug("KEX done"); | 1812 | debug("KEX done"); |
1802 | } | 1813 | } |
1814 | |||
1815 | /* server specific fatal cleanup */ | ||
1816 | void | ||
1817 | cleanup_exit(int i) | ||
1818 | { | ||
1819 | if (the_authctxt) | ||
1820 | do_cleanup(the_authctxt); | ||
1821 | _exit(i); | ||
1822 | } | ||