]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
last: make is_phantom() when kernel config does not include audit support
authorSami Kerola <kerolasa@iki.fi>
Mon, 11 Aug 2014 22:04:26 +0000 (23:04 +0100)
committerSami Kerola <kerolasa@iki.fi>
Fri, 19 Sep 2014 18:31:01 +0000 (19:31 +0100)
When kernel CONFIG_AUDIT is not set the /proc/<pid>/loginuid information
is not present resulting live sessions to be marked 'gone - no logout' in
last(1) print out.  To go-around this change makes last(1) to look
/dev/<tty> device ownership as a substitute of loginuid.

The go-around seems to work fairly well, but it has it short comings.
For example after closing a X window session the /dev/ttyN file seems to
be owned by root, not the user who had it before entering to the X
session.  While that is suboptimal it is still better than an attmempt to
determine uid_t by looking owner of the /proc/<struct utmp ut_pid>, that
is a login(1) process running as root.

The issue was found using Archlinux installation.

$ pacman -Qi linux
Name           : linux
Version        : 3.16-2
[...]
Build Date     : Mon Aug 4 18:06:51 2014

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
login-utils/last.c

index f7a2576f4484940a6d809d7c508d45ce517df9bb..fb82f31c0339c6a8e215bc0ecca3065e0a070029 100644 (file)
@@ -582,8 +582,6 @@ static int is_phantom(const struct last_control *ctl, struct utmp *ut)
 {
        struct passwd *pw;
        char path[32];
-       FILE *f = NULL;
-       unsigned int loginuid;
        int ret = 0;
 
        if (ut->UL_UT_TIME < ctl->boot_time.tv_sec)
@@ -592,14 +590,26 @@ static int is_phantom(const struct last_control *ctl, struct utmp *ut)
        if (!pw)
                return 1;
        sprintf(path, "/proc/%u/loginuid", ut->ut_pid);
-       if (access(path, R_OK) != 0 || !(f = fopen(path, "r")))
-               return 1;
+       if (access(path, R_OK) == 0) {
+               unsigned int loginuid;
+               FILE *f = NULL;
+
+               if (!(f = fopen(path, "r")))
+                       return 1;
+               if (fscanf(f, "%u", &loginuid) != 1)
+                       ret = 1;
+               fclose(f);
+               if (!ret && pw->pw_uid != loginuid)
+                       return 1;
+       } else {
+               struct stat st;
 
-       if (fscanf(f, "%u", &loginuid) != 1)
-               ret = 1;
-       fclose(f);
-       if (!ret && pw->pw_uid != loginuid)
-               return 1;
+               sprintf(path, "/dev/%s", ut->ut_line);
+               if (stat(path, &st))
+                       return 1;
+               if (pw->pw_uid != st.st_uid)
+                       return 1;
+       }
        return ret;
 }