When you run groups username
, it looks up1 the given user in /etc/passwd
and /etc/group
(although it can be LDAP, NIS or something else2) and shows you all groups found.
On the other hand, when you run the groups
command without any arguments, it simply lists all groups it itself belongs to3 – which is not necessarily the same as what is listed in /etc/group
. (See below for an explanation.) In fact, the only lookups made to /etc/group
are for translating GIDs to group names.
Each process has a set of credentials, which contains (among other things) a "real group ID" (primary GID), an "effective group ID" (EGID), and a list of "supplementary group" IDs (secondary GIDs). By default, a process inherits its credentials from its parent; however, processes running as root (UID 0) or having the CAP_SETUID
capability are allowed to set arbitrary credentials.
In particular, when you log in to Linux (whether in a tty, X11, or over SSH), the login process (/bin/login, gdm, sshd) looks up your username to determine your UID, primary GID, and secondary GIDs. On a personal machine, this just means reading the appropriate lines from passwd
and group
files (or NIS, LDAP, etc).
Next, the login process switches4 to those credentials before starting your session, and every process you launch from now on will have the exact same UID & GIDs – the system does not check /etc/group
anymore5 and will not pick up any modifications made.
In this way, the /usr/bin/groups
process will belong to the same groups as you did when you logged in, not what the database says you are in.
Note: The above explanation also applies to almost all Unixes; to the Windows NT family (except UIDs and GIDs are all called "SIDs", there is no "primary group", the credentials are called the "process token", and CAP_SETUID
is SeCreateTokenPrivilege or SeTcbPrivilege); and likely to most other multi-user operating systems.
1 getpwuid() and getgrouplist() are used to look up a user's groups.
2 On Linux, glibc uses /etc/nsswitch.conf
to determine where to look for this information.
3 groups
uses getgid(), getegid() and getgroups() to obtain its own credentials.
4 setuid(), setgid(), initgroups() and related.
5 An exception, of course, is the various tools that run elevated (setuid) such as su
, sudo
, sg
, newgrp
, pkexec
, and so on. This means that su $USER
will spawn a shell with the updated group list.
1There are so many duplicates of this question that I don't even know where to start. – user1686 – 2012-04-24T21:39:38.777