---
title: 'Users and Groups'
source: 'https://academia.sh/en/courses/introduction-to-linux/users-and-groups'
course: 'Introduction to Linux'
language: en
updated: '2026-08-17T18:09:57+00:00'
license: 'CC BY-SA 4.0'
---

# 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.

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.
