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);
 }
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to