From owner-svn-src-all@FreeBSD.ORG Wed Apr 9 21:19:47 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3FA389B6; Wed, 9 Apr 2014 21:19:47 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 20F9E1196; Wed, 9 Apr 2014 21:19:47 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s39LJkTL042549; Wed, 9 Apr 2014 21:19:46 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s39LJkUv042548; Wed, 9 Apr 2014 21:19:46 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201404092119.s39LJkUv042548@svn.freebsd.org> From: Jilles Tjoelker Date: Wed, 9 Apr 2014 21:19:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r264309 - stable/9/usr.bin/login X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Apr 2014 21:19:47 -0000 Author: jilles Date: Wed Apr 9 21:19:46 2014 New Revision: 264309 URL: http://svnweb.freebsd.org/changeset/base/264309 Log: MFC r261193: login: Clean up PAM and audit, then exit, on SIGHUP and SIGTERM This avoids leaving stale entries in utmpx after the connection is closed on an open login session. It also allows a clean way (SIGTERM) to forcibly terminate a user's terminal session. This does not affect the situation for "hung" processes after the connection is closed. The foreground process group receives SIGHUP and the tty becomes inaccessible. Also replace all use of the obsolete signal() function with sigaction() (not only the part where it is actually required: SIGHUP and SIGTERM must mask the other as well when caught). PR: misc/183495 Modified: stable/9/usr.bin/login/login.c Directory Properties: stable/9/usr.bin/login/ (props changed) Modified: stable/9/usr.bin/login/login.c ============================================================================== --- stable/9/usr.bin/login/login.c Wed Apr 9 20:42:00 2014 (r264308) +++ stable/9/usr.bin/login/login.c Wed Apr 9 21:19:46 2014 (r264309) @@ -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 *, cons 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); }