Home/Linux Administration/Users & Permissions
🔐

Level 4 of 24

Users & Permissions

Users, groups, sudo, and the permission model that protects every file on the system.

Almost every "why can't I access this" or "why did that break" question on a Linux system traces back to users, groups, or permissions. This level covers the model in enough depth that permission problems become quick to diagnose instead of a source of dread.

Prerequisites

  • • Level 3: Filesystem

By the end of this level, you can

  • ✓ Explain UID/GID and where user/group data actually lives
  • ✓ Create and manage users and groups confidently
  • ✓ Read any `ls -l` permission string instantly
  • ✓ Configure least-privilege sudo access instead of full root

Users, groups, and where their data lives

/etc/passwd, /etc/shadow, /etc/group, and the commands that manage them. · 9 min

Every user account has a numeric User ID (UID) — the kernel and filesystem only ever deal in UIDs, not usernames; the username is a convenience layer resolved via `/etc/passwd`. UID 0 is always root, the superuser with unrestricted access. Regular user UIDs conventionally start at 1000 on most modern distributions, with UIDs below that reserved for system accounts and services that need their own identity but aren't meant for interactive login.

`/etc/passwd` lists every user account: username, UID, primary GID, a description field, home directory, and login shell — despite the name, it hasn't stored actual passwords in decades; that field is now always an `x`, a placeholder pointing to `/etc/shadow`. `/etc/shadow` holds the actual (hashed, never plaintext) passwords and password-aging policy, and is readable only by root — this separation exists specifically so that `/etc/passwd`, which many tools need to read to resolve usernames, doesn't need to expose password hashes to do so.

`/etc/group` lists every group, its GID, and its member usernames. Every user has exactly one primary group (assigned at creation, usually matching their username by default) but can belong to any number of supplementary groups, which is how you grant access to shared resources (a "developers" group with write access to a shared directory) without changing anyone's primary identity.

CommandPurposeExample
useraddCreate a new user accountsudo useradd -m -s /bin/bash alice
usermodModify an existing user accountsudo usermod -aG developers alice
userdelDelete a user accountsudo userdel -r alice # -r also removes their home directory
passwdSet or change a user's password—
groupaddCreate a new groupsudo groupadd developers
idShow a user's UID, primary GID, and all supplementary group membershipsid alice
groupsList the groups a user belongs to—

Common Mistakes

  • ⚠ Using `usermod -G` (capital G, no `-a`) to add a supplementary group — this replaces ALL existing supplementary groups instead of adding one, silently removing the user from every other group they were in
  • ⚠ Forgetting `-m` when creating a user with `useradd`, resulting in no home directory being created
  • ⚠ Assuming deleting a user (`userdel`) also removes files they own elsewhere on the system — it doesn't, by default, outside their home directory
🧪

Hands-On Lab

Create users and a shared group

Objectives

  • ✓ Create two new user accounts with home directories
  • ✓ Create a shared group and add both users to it
  • ✓ Verify group membership without guessing

Instructions

  1. Create user `alice` with `sudo useradd -m -s /bin/bash alice`, then set her password with `sudo passwd alice`.
  2. Repeat for a user `bob`.
  3. Create a group called `project-team` with `sudo groupadd project-team`.
  4. Add both `alice` and `bob` to `project-team` as a supplementary group using `usermod -aG` (note the `-a` — append, don't replace).
  5. Confirm both memberships with `id alice` and `id bob`, checking that `project-team` appears in each output.
Hints (1)
  • If a user doesn't see their new group membership immediately, they may need to log out and back in — group membership is evaluated at login time, not live.

Takeaway: `/etc/passwd` is world-readable identity data; `/etc/shadow` is root-only secret data — that split is exactly why so many tools can resolve "UID 1001 = alice" without ever touching a password hash.

sudo, visudo, and least-privilege administration

Why "just log in as root" is the wrong habit, and how to configure sudo properly. · 9 min

`su` switches you to another user (commonly root) for the rest of the session, requiring that user's own password. `sudo` runs a single command as another user (by default root), requiring your own password, and logs what was run — a meaningful audit trail that "log in as root directly" doesn't give you. Modern practice strongly favors `sudo` over routine root logins: it preserves accountability (which admin ran what, and when), and lets you grant a specific person access to specific commands without handing over full root.

`/etc/sudoers` controls who can run what as whom, and must never be edited directly with a normal text editor — a syntax error in this file can lock every administrator out of `sudo` simultaneously, including yourself. `visudo` opens the file for editing through a wrapper that validates syntax before saving, refusing to write a broken file. This single habit (always `visudo`, never `vim /etc/sudoers` directly) prevents a specific, well-known class of self-inflicted outage.

The real power of `sudoers` is scoping access narrowly instead of granting blanket root: a line like `alice ALL=(ALL) /usr/bin/systemctl restart nginx` lets alice restart exactly that one service with sudo, and nothing else — no file access, no other commands, no full root shell. This is the least-privilege principle applied directly to system administration: grant exactly the access a role needs, not a convenient superset "to save time".

CommandPurposeExample
sudoRun a single command with elevated (by default root) privilegessudo systemctl restart nginx
sudo -lList the sudo privileges available to the current user—
visudoSafely edit /etc/sudoers with syntax validation before saving—
su - usernameSwitch to another user's full login session (the dash loads their environment too)—

Scoped sudoers entry — one command, not full root

# /etc/sudoers (edit only via visudo)
alice ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx

# alice can now run exactly this, without a password prompt,
# and nothing else requires sudo for her.

Common Mistakes

  • ⚠ Editing /etc/sudoers directly with a text editor instead of visudo — one syntax error can lock out every admin's sudo access at once
  • ⚠ Granting `ALL=(ALL) ALL` to everyone "to keep things simple" instead of scoping to what a role actually needs
  • ⚠ Using NOPASSWD broadly instead of only for specific, low-risk, frequently-run commands

Takeaway: Always edit /etc/sudoers through `visudo`, never directly — and scope sudo access to the specific commands a role needs instead of defaulting everyone to full root.

File permissions: rwx, chmod, and chown

Reading `-rwxr-xr--` instantly, and the numeric shorthand behind chmod 755. · 11 min

Every file has three permission sets — for its owner, its group, and everyone else ("others") — and three permission types within each: read (r), write (w), and execute (x). Run `ls -l` and the first ten characters of each line encode this: the first character is the file type (`-` for a regular file, `d` for a directory, `l` for a symlink), then three groups of three characters for owner/group/others permissions. `-rwxr-xr--` means: a regular file, owner can read/write/execute, group can read/execute, others can only read.

For directories specifically, permissions mean something slightly different than for files: read lets you list the directory's contents, write lets you create/delete/rename entries inside it, and execute lets you actually enter it (`cd` into it) or access files inside it by path — a directory with read but not execute permission will let you see filenames via `ls` but not open any of them, which surprises people the first time they hit it.

Numerically, each permission has a value — read=4, write=2, execute=1 — and you sum them per group: `rwx` = 4+2+1 = 7, `r-x` = 4+1 = 5, `r--` = 4. So `chmod 755 file` sets owner to rwx (7), group to r-x (5), others to r-x (5) — the standard permission for an executable script or directory others need to traverse. `chmod 644` (rw-r--r--) is the standard for a regular, non-executable file. `chmod 600` (rw-------) means only the owner can read or write it at all — the correct permission for anything containing a secret, like an SSH private key.

CommandPurposeExample
chmodChange file permissions (numeric or symbolic)chmod 755 script.sh chmod u+x script.sh
chownChange file owner (and optionally group)chown alice:developers file.txt
chgrpChange only the group of a filechgrp developers file.txt
umaskShow or set the default permission mask applied to newly created files—

Reading a permission string

-rwxr-xr--  1 alice developers  1024  Sep 19 10:00  deploy.sh
│└┬┘└┬┘└┬┘
│ │  │  └─ others: r-- (read only)
│ │  └──── group:  r-x (read + execute)
│ └─────── owner:  rwx (read + write + execute)
└───────── file type: - (regular file)

Common Mistakes

  • ⚠ Running `chmod 777` to "just make the permission error go away" instead of diagnosing the actual owner/group mismatch — this grants write access to literally everyone on the system
  • ⚠ Forgetting that a directory needs execute permission to be entered, not just read permission to be listed
  • ⚠ Setting overly permissive permissions on private keys or credential files instead of 600

Quick Check

What does chmod 640 set as the permission for "others" (everyone besides owner and group)?

Takeaway: Never reach for `chmod 777` as a fix — it grants full access to everyone on the system, and almost always means the real problem (wrong owner, wrong group) hasn't actually been diagnosed.

SUID, SGID, and the sticky bit

The three special permission bits that don't fit the standard rwx model, and why /tmp needs one of them. · 6 min

SUID (Set User ID), when set on an executable file, makes it run with the permissions of the file's owner rather than the user who launched it — this is how `passwd` lets a regular, unprivileged user update their own password even though `/etc/shadow` is only writable by root: the `passwd` binary itself runs as root momentarily via SUID, does the specific privileged write it needs to do, and exits.

SGID (Set Group ID) has two distinct effects depending on what it's applied to: on an executable, it runs with the file's group permissions instead of the invoking user's group. On a directory, it makes new files and subdirectories created inside automatically inherit that directory's group, instead of the creating user's primary group — genuinely useful for shared team directories where you want every new file to automatically belong to the team's group.

The sticky bit, applied to a directory, restricts deletion: even if multiple users have write access to that directory, each user can only delete or rename files they personally own within it. `/tmp` is the canonical example — everyone needs to write temporary files there, but you don't want any user able to delete another user's temp files.

CommandPurposeExample
chmod u+s fileSet the SUID bitchmod 4755 file # leading 4 = SUID
chmod g+s dirSet the SGID bitchmod 2775 dir # leading 2 = SGID
chmod +t dirSet the sticky bitchmod 1777 dir # leading 1 = sticky

Spotting these bits in ls -l output

-rwsr-xr-x  # SUID set (s instead of x in owner's execute position)
drwxrwsr-x  # SGID set on a directory (s in group's execute position)
drwxrwxrwt  # Sticky bit set (t instead of x in others' execute position) — this is /tmp

Takeaway: These three bits solve three specific, narrow problems (temporary privilege escalation, group inheritance, and shared-directory delete protection) — they're not general-purpose permission shortcuts, and misapplied SUID on the wrong binary is a real privilege-escalation risk.

Sponsor / Advertisement