diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c index 166dfdc5456c..6ba15dc0e908 100644 --- a/usr.bin/login/login.c +++ b/usr.bin/login/login.c @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$"); static int auth_pam(void); static void bail(int, int); +static void bail_internal(int, int, int); static int export(const char *); static void export_pam_environment(void); static int motd(const char *); @@ -94,6 +95,7 @@ static void refused(const char *, const char *, int); static const char *stypeof(char *); static void sigint(int); static void timedout(int); +static void bail_sig(int); static void usage(void); #define TTYGRPNAME "tty" /* group to own ttys */ @@ -172,13 +174,18 @@ main(int argc, char *argv[]) login_cap_t *lc = NULL; login_cap_t *lc_user = NULL; pid_t pid; + sigset_t mask, omask; + struct sigaction sa; #ifdef USE_BSM_AUDIT char auditsuccess = 1; #endif - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGHUP, SIG_IGN); + sa.sa_flags = SA_RESTART; + (void)sigfillset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + (void)sigaction(SIGQUIT, &sa, NULL); + (void)sigaction(SIGINT, &sa, NULL); + (void)sigaction(SIGHUP, &sa, NULL); if (setjmp(timeout_buf)) { if (failures) badlogin(username); @@ -186,7 +193,8 @@ main(int argc, char *argv[]) timeout); bail(NO_SLEEP_EXIT, 0); } - (void)signal(SIGALRM, timedout); + sa.sa_handler = timedout; + (void)sigaction(SIGALRM, &sa, NULL); (void)alarm(timeout); (void)setpriority(PRIO_PROCESS, 0, 0); @@ -370,7 +378,14 @@ main(int argc, char *argv[]) /* committed to login -- turn off timeout */ (void)alarm((u_int)0); - (void)signal(SIGHUP, SIG_DFL); + + (void)sigemptyset(&mask); + (void)sigaddset(&mask, SIGHUP); + (void)sigaddset(&mask, SIGTERM); + (void)sigprocmask(SIG_BLOCK, &mask, &omask); + sa.sa_handler = bail_sig; + (void)sigaction(SIGHUP, &sa, NULL); + (void)sigaction(SIGTERM, &sa, NULL); endpwent(); @@ -550,10 +565,17 @@ main(int argc, char *argv[]) /* * Parent: wait for child to finish, then clean up * session. + * + * If we get SIGHUP or SIGTERM, clean up the session + * and exit right away. This will make the terminal + * inaccessible and send SIGHUP to the foreground + * process group. */ int status; setproctitle("-%s [pam]", getprogname()); + (void)sigprocmask(SIG_SETMASK, &omask, NULL); waitpid(pid, &status, 0); + (void)sigprocmask(SIG_BLOCK, &mask, NULL); bail(NO_SLEEP_EXIT, 0); } @@ -627,10 +649,15 @@ main(int argc, char *argv[]) login_close(lc_user); login_close(lc); - (void)signal(SIGALRM, SIG_DFL); - (void)signal(SIGQUIT, SIG_DFL); - (void)signal(SIGINT, SIG_DFL); - (void)signal(SIGTSTP, SIG_IGN); + sa.sa_handler = SIG_DFL; + (void)sigaction(SIGALRM, &sa, NULL); + (void)sigaction(SIGQUIT, &sa, NULL); + (void)sigaction(SIGINT, &sa, NULL); + (void)sigaction(SIGTERM, &sa, NULL); + (void)sigaction(SIGHUP, &sa, NULL); + sa.sa_handler = SIG_IGN; + (void)sigaction(SIGTSTP, &sa, NULL); + (void)sigprocmask(SIG_SETMASK, &omask, NULL); /* * Login shells have a leading '-' in front of argv[0] @@ -847,17 +874,20 @@ sigint(int signo __unused) static int motd(const char *motdfile) { - sig_t oldint; + struct sigaction newint, oldint; FILE *f; int ch; if ((f = fopen(motdfile, "r")) == NULL) return (-1); motdinterrupt = 0; - oldint = signal(SIGINT, sigint); + newint.sa_handler = sigint; + newint.sa_flags = 0; + sigfillset(&newint.sa_mask); + sigaction(SIGINT, &newint, &oldint); while ((ch = fgetc(f)) != EOF && !motdinterrupt) putchar(ch); - signal(SIGINT, oldint); + sigaction(SIGINT, &oldint, NULL); if (ch != EOF || ferror(f)) { fclose(f); return (-1); @@ -966,12 +996,10 @@ pam_cleanup(void) } } -/* - * Exit, optionally after sleeping a few seconds - */ -void -bail(int sec, int eval) +static void +bail_internal(int sec, int eval, int signo) { + struct sigaction sa; pam_cleanup(); #ifdef USE_BSM_AUDIT @@ -979,5 +1007,36 @@ bail(int sec, int eval) audit_logout(); #endif (void)sleep(sec); - exit(eval); + if (signo == 0) + exit(eval); + else { + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + (void)sigemptyset(&sa.sa_mask); + (void)sigaction(signo, &sa, NULL); + (void)sigaddset(&sa.sa_mask, signo); + (void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); + raise(signo); + exit(128 + signo); + } +} + +/* + * Exit, optionally after sleeping a few seconds + */ +static void +bail(int sec, int eval) +{ + bail_internal(sec, eval, 0); +} + +/* + * Exit because of a signal. + * This is not async-signal safe, so only call async-signal safe functions + * while the signal is unmasked. + */ +static void +bail_sig(int signo) +{ + bail_internal(NO_SLEEP_EXIT, 0, signo); }