How POSIX User ID and Supplementary Group IDs are Set On Login

This is usually done by the login(1) setuid executable.

It looks up /etc/passwd with the username and gets the User ID and the Primary Group ID. This is the 0:0 in /etc/passwd.

root:*:0:0:Superuser:/root:/usr/local/bin/fish

It looks up /etc/group with the username and gets all the groups the user is in (Supplementary Group IDs).

Then, it spawns a shell (the shell command is also read from /etc/passwd) in a new session (kernel concept) with the User ID, Primary Group ID, Supplementary Group IDs. It also sets $USER and other environment variables.


One uid can have multiple names, and one gid can have multiple names.

Here’s an example from FreeBSD:

/etc/passwd:

root:*:0:0:Superuser:/root:/usr/local/bin/fish
toor:*:0:0:Bourne-again Superuser:/root:

/etc/group:

wheel:*:0:root
operator:*:5:root

Now observe the magic:

user@ed ~> doas -s -u root
root@ed ~# groups
wheel operator
root@ed ~# exit
user@ed ~> doas -s -u toor
toor@ed ~# groups
wheel

An even more cursed idea:

root:*:0:0::/root:
toor:*:0:5::/root:

As it turns out, the source of uid/gid comes is less straightforward than simply reading /etc/passwd. libc (providing getpwent(3) and family) reads /etc/nsswitch.conf to see if it should access /etc/passwd or some other place.

Authentication modules like pam_unix.so in Linux-PAM uses getpwent(3) to check passwords of UNIX users.


Update(2024-07-07): Don’t know where else to put it, so I’m putting it here.

On OpenBSD, doas(1) sets an attribute on the controlling terminal with ioctl(2). I wonder what other ways one can associate metadata with tty.