Lesson 12 / 20
Users and Groups
Identity held as a number at the kernel level, the field structure of the account and group files, the distinction between primary and supplementary groups, and name resolution.
Contents
The previous lesson’s output belonged to the backup account for files on the remote
machine, and to a different account for local files. The owner and group columns in listing
output had been visible from the start, but were never explained.
This lesson closes that gap. What identity is stored as on the system is the input to the next lesson’s permission check: when the kernel answers “can this user read this file,” it compares exactly these values.
Identity Is a Number
The kernel does not know usernames. What every process is associated with is two integers: the user ID (UID) and the group ID (GID). Names exist only for humans and are resolved by programs in user space.
$ id uid=1001(student) gid=1001(student) groups=1001(student),2001(project)
The output gives three pieces of information: the user ID, the primary group ID, and every group the user belongs to. The names in parentheses are the resolved counterparts of the numbers; the actual value is the number.
The fields can also be requested separately:
$ id -u 1001 $ id -g 1001 $ id -un student
The -n suffix gives the name instead of the number. The whoami command produces the same
result as id -un.
The practical consequence: a file’s owner is not a name, it is a number. If a user is deleted and a new account opens with the same number, the old files appear to belong to the new account. Likewise, files extracted from an archive can land on a different person’s ownership on the target system — what an archive stores is also the number.
Root is the account whose UID value is zero. Its privilege comes not from its name but from this number; the kernel skips most checks for UID zero.
The Account File
Account records are kept in a text file. Each line is one account, and fields are separated by colons:
$ grep -E '^(root|student|backup):' /etc/passwd root:x:0:0:root:/root:/bin/bash student:x:1001:1001::/home/student:/bin/bash backup:x:1002:1002::/home/backup:/bin/bash
The seven fields, in order, are:
| Order | Field | Value in the example |
|---|---|---|
| 1 | Username | student |
| 2 | Password placeholder | x |
| 3 | User ID | 1001 |
| 4 | Primary group ID | 1001 |
| 5 | Comment field | empty |
| 6 | Home directory | /home/student |
| 7 | Login shell | /bin/bash |
This file’s format was already read from section five of the manual in the Help Resources lesson; this is the concrete example of what section 5 is for.
The x in the second field is not a password. Password hashes are kept in a separate file
that only root can read:
$ ls -l /etc/passwd /etc/shadow -rw-r--r-- 1 root root 1236 Jul 26 19:14 /etc/passwd -rw-r----- 1 root shadow 668 Jul 26 19:14 /etc/shadow $ cat /etc/shadow cat: /etc/shadow: Permission denied
The reason for the separation shows up in the permission columns: the account file is
readable by everyone (rw-r--r--), because every program needs access to the username-to-ID
mapping. If password hashes had the same accessibility, anyone could take the hashes and
attempt offline cracking. Hashes are therefore separated and are readable only by their owner
and the shadow group.
System accounts and human accounts are separated by ID ranges. Low numbers are reserved for services; human accounts start above a threshold that depends on the system’s configuration, but the separation itself is general, and account-creation tools pick the number from within this range.
The shell in the seventh field runs when a session opens. For service accounts where login is not wanted, this field holds a program that terminates immediately when run — the standard way to disable an account.
The Account’s Life Cycle
Account files are not edited by hand; account-management commands update these files consistently. A command that opens a new account writes not to one file but to three at once: a line in the account file, a password record in the shadow file, the primary group in the group file. It also creates the home directory and copies starting configuration files into it from the skeleton directory.
Supplementary group membership can be granted afterward. A common misconception: membership added at that moment is not reflected in the running session. A process’s group list is determined when the session opens and stays fixed for its duration; new membership only takes effect in a new session.
Closing an account and deleting it are separate operations. Closing invalidates the password, or replaces the login shell with a program that terminates the session; identity and file ownership stay in place. Deletion removes the record from the files — but does not clean up the files the user left on the system.
The result is a direct, visible consequence of identity being a number:
$ ls -l /data/report.txt -rw-r--r-- 1 student student 0 Jul 26 19:54 /data/report.txt $ sudo userdel student $ ls -l /data/report.txt -rw-r--r-- 1 1001 1001 0 Jul 26 19:54 /data/report.txt
A number appears in the owner column instead of a name: ownership has not changed, only the record that would translate the number into a name is gone. Such files silently belong to whoever gets that same number next — what needs handing over or cleaning up when an account is deleted.
The Group File
Groups are kept in a separate file, with four fields:
$ grep -E '^(root|student|backup|project):' /etc/group root:x:0: student:x:1001: project:x:2001:student backup:x:1002:
The fields, in order, are the group name, the password placeholder, the group ID, and the list of supplementary members.
The last field deserves attention. The student group’s member list is empty, yet the
student user is a member of this group. That is not a contradiction: membership comes from
two separate places.
The primary group is in the account file’s fourth field. New files a user creates take this group by default.
Supplementary groups come from the group file’s member lists. The line
project:x:2001:student makes the student user a supplementary member of the project
group.
Total membership is the union of both sources:
$ groups student project
Giving every user a primary group named after themselves is a common configuration. The reason will be seen in the permission bits lesson: if the primary group were a shared group, every file a user creates would by default be open to that group.
A separate project group has been defined for this course’s project tree. It will be used to
open the tree up for sharing in the ownership, group, and special permission bits lessons.
Name Resolution
Identity information does not always come from local files. At organizational scale, accounts can be kept in a directory service on the network, so programs call a resolution layer instead of reading the files directly.
$ getent passwd student student:x:1001:1001::/home/student:/bin/bash $ getent group project project:x:2001:student
The getent command queries every configured source on the system and gives the answer in a
standard format. Even when a record sits on a network source rather than in a local file, the
output has the same shape; the program calling the command does not need to know where the
source is.
In practice this means whether an account exists is tested not by grepping a file but by
asking with getent. Not being found in the file does not show that the account does not
exist.
Account Management Commands
The commands for creating, modifying, and deleting accounts and groups require root privilege and are documented in the manual’s eighth section. No account will be opened in this course; the related tool family is the subject of the System Administration course.
The one common operation that does not require root privilege is a user changing their own password. How this is possible is an interesting question: the file holding password hashes cannot even be read by an ordinary user, so how is writing to it made possible?
$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 72056 May 30 2024 /usr/bin/passwd
There is an unusual character in the permission string: an s instead of an x at the third
position of the owner permissions. This is the subject of the special permission bits lesson,
and it will be answered at that topic’s close.
Summary
- The kernel stores identity as a number; names are resolved in user space, and file ownership is bound to the number.
- Root’s privilege comes not from its name but from the user ID being zero.
- The account file carries seven fields: name, password placeholder, user ID, primary group ID, comment, home directory, and login shell.
- Password hashes sit in a separate, privilege-only-readable file to prevent offline cracking attacks.
- Membership comes from two sources: the primary group in the account file and the supplementary member lists in the group file.
- Name resolution is not limited to local files; queries go through a resolution layer.
Next Step
Now that identity is defined, what this identity can do to a file can be asked. The next lesson resolves the nine characters in the first column of listing output: three access types, three user classes, octal notation, and why the same bits mean something entirely different in directories.
To keep your progress and take notes, Log in
My notes
Log in to take notes.