login: fix /etc/nologin handling (should prohibit non-root LOGINS,
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 7 Nov 2008 12:59:31 +0000 (12:59 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 7 Nov 2008 12:59:31 +0000 (12:59 -0000)
 not running login by non-root). minor code shrink.

function                                             old     new   delta
login_main                                          1669    1602     -67

loginutils/login.c

index 861382f..70e3b13 100644 (file)
@@ -52,7 +52,7 @@ static char* short_tty;
  *     command line flags.
  */
 
-static void read_or_build_utent(struct utmp *utptr, int picky)
+static void read_or_build_utent(struct utmp *utptr, int run_by_root)
 {
        struct utmp *ut;
        pid_t pid = getpid();
@@ -60,30 +60,33 @@ static void read_or_build_utent(struct utmp *utptr, int picky)
        setutent();
 
        /* First, try to find a valid utmp entry for this process.  */
-       while ((ut = getutent()))
-               if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
-               (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
-                       break;
+       /* If there is one, just use it.  */
+       while ((ut = getutent()) != NULL)
+               if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0]
+                && (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)
+               ) {
+                       *utptr = *ut; /* struct copy */
+                       if (run_by_root) /* why only for root? */
+                               memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
+                       return;
+               }
 
-       /* If there is one, just use it, otherwise create a new one.  */
-       if (ut) {
-               *utptr = *ut;
-       } else {
-               if (picky)
-                       bb_error_msg_and_die("no utmp entry found");
-
-               memset(utptr, 0, sizeof(*utptr));
-               utptr->ut_type = LOGIN_PROCESS;
-               utptr->ut_pid = pid;
-               strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
-               /* This one is only 4 chars wide. Try to fit something
-                * remotely meaningful by skipping "tty"... */
-               strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
-               strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
-               utptr->ut_tv.tv_sec = time(NULL);
-       }
-       if (!picky)     /* root login */
-               memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
+// Why? Do we require non-root to exec login from another
+// former login process (e.g. login shell)? Some login's have
+// login shells as children, so it won't work...
+//     if (!run_by_root)
+//             bb_error_msg_and_die("no utmp entry found");
+
+       /* Otherwise create a new one.  */
+       memset(utptr, 0, sizeof(*utptr));
+       utptr->ut_type = LOGIN_PROCESS;
+       utptr->ut_pid = pid;
+       strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
+       /* This one is only 4 chars wide. Try to fit something
+        * remotely meaningful by skipping "tty"... */
+       strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
+       strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
+       utptr->ut_tv.tv_sec = time(NULL);
 }
 
 /*
@@ -109,7 +112,7 @@ static void write_utent(struct utmp *utptr, const char *username)
 #endif
 }
 #else /* !ENABLE_FEATURE_UTMP */
-#define read_or_build_utent(utptr, picky) ((void)0)
+#define read_or_build_utent(utptr, run_by_root) ((void)0)
 #define write_utent(utptr, username) ((void)0)
 #endif /* !ENABLE_FEATURE_UTMP */
 
@@ -225,7 +228,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
        char *fromhost;
        char username[USERNAME_SIZE];
        const char *tmp;
-       int amroot;
+       int run_by_root;
        unsigned opt;
        int count = 0;
        struct passwd *pw;
@@ -248,8 +251,9 @@ int login_main(int argc UNUSED_PARAM, char **argv)
        signal(SIGALRM, alarm_handler);
        alarm(TIMEOUT);
 
-       /* More of suid paranoia if called by non-root */
-       amroot = !sanitize_env_if_suid(); /* Clear dangerous stuff, set PATH */
+       /* More of suid paranoia if called by non-root: */
+       /* Clear dangerous stuff, set PATH */
+       run_by_root = !sanitize_env_if_suid();
 
        /* Mandatory paranoia for suid applet:
         * ensure that fd# 0,1,2 are opened (at least to /dev/null)
@@ -259,7 +263,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
 
        opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
        if (opt & LOGIN_OPT_f) {
-               if (!amroot)
+               if (!run_by_root)
                        bb_error_msg_and_die("-f is for root only");
                safe_strncpy(username, opt_user, sizeof(username));
        }
@@ -278,7 +282,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
                        short_tty = full_tty + 5;
        }
 
-       read_or_build_utent(&utent, !amroot);
+       read_or_build_utent(&utent, run_by_root);
 
        if (opt & LOGIN_OPT_h) {
                USE_FEATURE_UTMP(
@@ -396,10 +400,12 @@ int login_main(int argc UNUSED_PARAM, char **argv)
                        return EXIT_FAILURE;
                }
                username[0] = '\0';
-       }
+       } /* while (1) */
 
        alarm(0);
-       if (!amroot)
+       /* We can ignore /etc/nologin if we are logging in as root,
+        * it doesn't matter whether we are run by root or not */
+       if (pw->pw_uid != 0)
                die_if_nologin();
 
        write_utent(&utent, username);
@@ -433,7 +439,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
        fchmod(0, 0600);
 
        /* We trust environment only if we run by root */
-       if (ENABLE_LOGIN_SCRIPTS && amroot) {
+       if (ENABLE_LOGIN_SCRIPTS && run_by_root) {
                char *t_argv[2];
 
                t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");
@@ -479,14 +485,16 @@ int login_main(int argc UNUSED_PARAM, char **argv)
        // bb_setpgrp();
        // If this stuff is really needed, add it and explain why!
 
-       /* set signals to defaults */
-       signal(SIGALRM, SIG_DFL);
+       /* Set signals to defaults */
+       /*signal(SIGALRM, SIG_DFL); - not needed, we already set it
+        * to non-SIG_IGN, and on exec such signals are reset to SIG_DFL */
+
        /* Is this correct? This way user can ctrl-c out of /etc/profile,
         * potentially creating security breach (tested with bash 3.0).
         * But without this, bash 3.0 will not enable ctrl-c either.
         * Maybe bash is buggy?
         * Need to find out what standards say about /bin/login -
-        * should it leave SIGINT etc enabled or disabled? */
+        * should we leave SIGINT etc enabled or disabled? */
        signal(SIGINT, SIG_DFL);
 
        /* Exec login shell with no additional parameters */