Subject: bug#76876: logname output is often wrong when linked with glibc

From: Bruno Haible <[email-masked]>
Date: Sun, 09 Mar 2025 19:49:15 +0100

Nicolas Boos wrote:
> This page says that the result of the logname command and the LOGNAME
> variable must be the same:
> https://www.ibm.com/docs/en/aix/7.3?topic=l-logname-command

An AIX man page is not a specification for what we run on GNU systems.

> Thus, getlogin() implementations that use the LOGNAME or login_name
> variables such as musl, uclibc or even gnulib WIN32 seems fine.

getlogin() is used for security and auditing purposes, for example,
for recording who has made important system changes as 'root'.

The problem with getenv("LOGNAME") is that it is arbitrarily fakeable.
For some uses, this may be fine. For other uses, it is not. And it's
for the latter that POSIX specified the getlogin() function that
accesses system-internal data structures that are not fakeable.
(If every use-case was happy with getenv("LOGNAME"), there would be
no need for a getlogin() function in POSIX.)

> Anyway, using a UID to get a login name like glibc's getlogin() function
> does, we sometimes get incorrect results.
> 
> Here is a third test case, allowed by posix:
> $ cat /etc/passwd
> nicolas:x:1000:2001::/home/nicolas:/bin/bash
> claude:x:1000:2002::/home/claude:/bin/zsh
> 
> localhost login: claude
> Password:
> $ echo $LOGNAME
> claude
> $ logname (glibc)
> nicolas
> $ logname (musl)
> claude
> $ logname (uclibc)
> claude

Yes, POSIX [1] says "If getlogin() returns a non-null pointer, then that
pointer points to the name that the user logged in under, even if there
are several login names with the same user ID." This can be implemented
on systems like FreeBSD, where the kernel keeps track of the user name
as a string. But on Linux,
  - The kernel keeps track only of the uid, which - as you noted - can
    be associated with several user names,
  - The database which associates ttys with login *names* is utmp, which
    on musl libc does not exist (see this definition in <utmp.h>:
    #define _PATH_UTMP "/dev/null/utmp"  ).
  - Even on systems which have /var/run/utmp, often the pseudo-ttys
    (allocated by terminal emulators) have no entry in /var/run/utmp;
    thus finding the "seat" of the screen on which a terminal emulator
    is running is hard.

Thus, on Linux systems, a correct implementation of getlogin() can not
distinguish different users with the same uid (with reasonable effort).
This applies to both glibc and the new code in gnulib.

Bruno

[1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/getlogin.html