X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/762715cee0114dae4b3ec201df5a7e22684dffb8..c6f1f67c6baeb6d5b35250a90e3e2855ff464278:/sshd.c diff --git a/sshd.c b/sshd.c index b6e71d84..2f810b9c 100644 --- a/sshd.c +++ b/sshd.c @@ -42,12 +42,16 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.234 2002/03/19 10:49:35 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.244 2002/05/29 11:21:57 markus Exp $"); #include #include #include #include +#ifdef HAVE_SECUREWARE +#include +#include +#endif #include "ssh.h" #include "ssh1.h" @@ -198,7 +202,7 @@ int *startup_pipes = NULL; int startup_pipe; /* in child */ /* variables used for privilege separation */ -extern struct monitor *monitor; +extern struct monitor *pmonitor; extern int use_privsep; /* Prototypes for various functions defined later in this file. */ @@ -276,10 +280,12 @@ sigterm_handler(int sig) static void main_sigchld_handler(int sig) { + pid_t pid; int save_errno = errno; int status; - while (waitpid(-1, &status, WNOHANG) > 0) + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) ; signal(SIGCHLD, main_sigchld_handler); @@ -372,7 +378,7 @@ sshd_exchange_identification(int sock_in, int sock_out) fatal_cleanup(); } - /* Read other side's version identification. */ + /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { @@ -521,6 +527,7 @@ privsep_preauth_child(void) { u_int32_t rand[256]; int i; + struct passwd *pw; /* Enable challenge-response authentication for privilege separation */ privsep_challenge_enable(); @@ -532,35 +539,79 @@ privsep_preauth_child(void) /* Demote the private keys to public keys. */ demote_sensitive_data(); + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + endpwent(); + /* Change our root directory*/ if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, strerror(errno)); if (chdir("/") == -1) - fatal("chdir(/)"); + fatal("chdir(\"/\"): %s", strerror(errno)); /* Drop our privileges */ - setegid(options.unprivileged_group); - setgid(options.unprivileged_group); - seteuid(options.unprivileged_user); - setuid(options.unprivileged_user); + debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, + (u_int)pw->pw_gid); + do_setusercontext(pw); } -static void -privsep_postauth(Authctxt *authctxt, pid_t pid) +static Authctxt* +privsep_preauth(void) { - extern Authctxt *x_authctxt; + Authctxt *authctxt = NULL; int status; + pid_t pid; - /* Wait for the child's exit status */ - waitpid(pid, &status, 0); + /* Set up unprivileged child process to deal with network data */ + pmonitor = monitor_init(); + /* Store a pointer to the kex for later rekeying */ + pmonitor->m_pkex = &xxx_kex; + + pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { + debug2("Network child is on pid %d", pid); + + close(pmonitor->m_recvfd); + authctxt = monitor_child_preauth(pmonitor); + close(pmonitor->m_sendfd); + + /* Sync memory */ + monitor_sync(pmonitor); + + /* Wait for the child's exit status */ + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + return (authctxt); + } else { + /* child */ + + close(pmonitor->m_sendfd); + + /* Demote the child */ + if (getuid() == 0 || geteuid() == 0) + privsep_preauth_child(); + setproctitle("%s", "[net]"); + } + return (NULL); +} + +static void +privsep_postauth(Authctxt *authctxt) +{ + extern Authctxt *x_authctxt; /* XXX - Remote port forwarding */ x_authctxt = authctxt; if (authctxt->pw->pw_uid == 0 || options.use_login) { /* File descriptor passing is broken or root login */ - monitor_apply_keystate(monitor); + monitor_apply_keystate(pmonitor); use_privsep = 0; return; } @@ -573,21 +624,21 @@ privsep_postauth(Authctxt *authctxt, pid_t pid) } /* New socket pair */ - monitor_reinit(monitor); + monitor_reinit(pmonitor); - monitor->m_pid = fork(); - if (monitor->m_pid == -1) + pmonitor->m_pid = fork(); + if (pmonitor->m_pid == -1) fatal("fork of unprivileged child failed"); - else if (monitor->m_pid != 0) { - debug2("User child is on pid %d", pid); - close(monitor->m_recvfd); - monitor_child_postauth(monitor); + else if (pmonitor->m_pid != 0) { + debug2("User child is on pid %d", pmonitor->m_pid); + close(pmonitor->m_recvfd); + monitor_child_postauth(pmonitor); /* NEVERREACHED */ exit(0); } - close(monitor->m_sendfd); + close(pmonitor->m_sendfd); /* Demote the private keys to public keys. */ demote_sensitive_data(); @@ -596,10 +647,9 @@ privsep_postauth(Authctxt *authctxt, pid_t pid) do_setusercontext(authctxt->pw); /* It is safe now to apply the key state */ - monitor_apply_keystate(monitor); + monitor_apply_keystate(pmonitor); } - static char * list_hostkey_types(void) { @@ -740,6 +790,9 @@ main(int ac, char **av) Key *key; int ret, key_used = 0; +#ifdef HAVE_SECUREWARE + (void)set_auth_parameters(ac, av); +#endif __progname = get_progname(av[0]); init_rng(); @@ -948,13 +1001,34 @@ main(int ac, char **av) } } + if (use_privsep) { + struct passwd *pw; + struct stat st; + + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || + (S_ISDIR(st.st_mode) == 0)) + fatal("Missing privilege separation directory: %s", + _PATH_PRIVSEP_CHROOT_DIR); + } + /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); -#ifdef HAVE_SCO_PROTECTED_PW - (void) set_auth_parameters(ac, av); -#endif +#ifndef HAVE_CYGWIN + /* + * Clear out any supplemental groups we may have inherited. This + * prevents inadvertent creation of files with bad modes (in the + * portable version at least, it's certainly possible for PAM + * to create a file, and we can't control the code in every + * module which might be used). + */ + if (setgroups(0, NULL) < 0) + debug("setgroups() failed: %.200s", strerror(errno)); +#endif /* !HAVE_CYGWIN */ /* Initialize the log (it is reinitialized below in case we forked). */ if (debug_flag && !inetd_flag) @@ -1272,6 +1346,17 @@ main(int ac, char **av) /* This is the child processing a new connection. */ + /* + * Create a new session and process group since the 4.4BSD + * setlogin() affects the entire process group. We don't + * want the child to be able to affect the parent. + */ +#if 0 + /* XXX: this breaks Solaris */ + if (setsid() < 0) + error("setsid: %.100s", strerror(errno)); +#endif + /* * Disable the key regeneration alarm. We will not regenerate the * key since we are no longer in a position to give it to anyone. We @@ -1345,7 +1430,7 @@ main(int ac, char **av) sshd_exchange_identification(sock_in, sock_out); /* * Check that the connection comes from a privileged port. - * Rhosts-Authentication only makes sense from priviledged + * Rhosts-Authentication only makes sense from privileged * programs. Of course, if the intruder has root access on his local * machine, he can connect from any port. So do not use these * authentication methods from machines that you do not trust. @@ -1374,36 +1459,9 @@ main(int ac, char **av) packet_set_nonblocking(); - if (!use_privsep) - goto skip_privilegeseparation; - - /* Set up unprivileged child process to deal with network data */ - monitor = monitor_init(); - /* Store a pointer to the kex for later rekeying */ - monitor->m_pkex = &xxx_kex; - - pid = fork(); - if (pid == -1) - fatal("fork of unprivileged child failed"); - else if (pid != 0) { - debug2("Network child is on pid %d", pid); - - close(monitor->m_recvfd); - authctxt = monitor_child_preauth(monitor); - close(monitor->m_sendfd); - - /* Sync memory */ - monitor_sync(monitor); - goto authenticated; - } else { - close(monitor->m_sendfd); - - /* Demote the child */ - if (getuid() == 0 || geteuid() == 0) - privsep_preauth_child(); - } - - skip_privilegeseparation: + if (use_privsep) + if ((authctxt = privsep_preauth()) != NULL) + goto authenticated; /* perform the key exchange */ /* authenticate user and start session */ @@ -1414,12 +1472,14 @@ main(int ac, char **av) do_ssh1_kex(); authctxt = do_authentication(); } - if (use_privsep) - mm_send_keystate(monitor); - - /* If we use privilege separation, the unprivileged child exits */ - if (use_privsep) + /* + * If we use privilege separation, the unprivileged child transfers + * the current keystate and exits + */ + if (use_privsep) { + mm_send_keystate(pmonitor); exit(0); + } authenticated: /* @@ -1427,7 +1487,8 @@ main(int ac, char **av) * file descriptor passing. */ if (use_privsep) { - privsep_postauth(authctxt, pid); + privsep_postauth(authctxt); + /* the monitor process [priv] will not return */ if (!compat20) destroy_sensitive_data(); } @@ -1679,7 +1740,7 @@ do_ssh1_kex(void) debug("Received session key; encryption turned on."); - /* Send an acknowledgement packet. Note that this packet is sent encrypted. */ + /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait();