Linux··4 min

Users and Groups — In Depth

The earlier permissions post covered the basics. This one goes deeper — how Linux stores user accounts in /etc/passwd and /etc/shadow, how to manage users properly, and how the sudoers file actually works.

The users and permissions post earlier covered the basics — owners, groups, chmod, chown. This post goes deeper. How does Linux actually store user accounts? How does sudo work under the hood? How do you manage users properly on a multi-user system?

/etc/passwd

Every user account on the system is defined in /etc/passwd.

cat /etc/passwd

Each line is one user and has seven fields separated by colons:

jan:x:1000:1000:Jan Doe:/home/jan:/bin/bash
  1. jan — username
  2. x — password field. The x means the password is stored in /etc/shadow instead (more on that below)
  3. 1000 — UID (User ID)
  4. 1000 — GID (primary Group ID)
  5. Jan Doe — GECOS field, a comment. Usually the full name.
  6. /home/jan — home directory
  7. /bin/bash — login shell

UIDs below 1000 are typically reserved for system accounts (daemons, services). Regular users start at 1000.

System accounts often have /usr/sbin/nologin or /bin/false as their shell — this prevents interactive login.

/etc/shadow

Passwords are not stored in /etc/passwd because that file is world-readable. Hashed passwords live in /etc/shadow, which is only readable by root.

sudo cat /etc/shadow
jan:$6$randomsalt$hashedpassword...:19480:0:99999:7:::

Fields:

  1. Username
  2. Hashed password ($6$ means SHA-512)
  3. Last password change (days since epoch)
  4. Minimum days before password can be changed
  5. Maximum days before password must be changed
  6. Warning days before expiry
  7. Days after expiry before account is disabled
  8. Account expiration date

A ! or * in the password field means the account is locked — no password login is possible.

/etc/group

Groups are defined in /etc/group:

cat /etc/group
sudo:x:27:jan,luca
docker:x:999:jan

Fields:

  1. Group name
  2. Password (almost always x or empty)
  3. GID
  4. Comma-separated list of members

Managing users

useradd

sudo useradd -m -s /bin/bash -c "Full Name" username
  • -m — create the home directory
  • -s /bin/bash — set the login shell
  • -c — comment (full name)

Without -m, no home directory is created. Always use it for real users.

Set a password:

sudo passwd username

usermod

Modify an existing user:

sudo usermod -aG docker jan       # add jan to the docker group
sudo usermod -s /bin/zsh jan      # change login shell
sudo usermod -L jan               # lock the account
sudo usermod -U jan               # unlock the account
sudo usermod -e 2026-12-31 jan    # set account expiry date

The -aG flag is important. -G alone replaces all supplementary groups. -aG appends. Forgetting the -a can remove a user from all their existing groups.

userdel

sudo userdel jan          # delete user but keep home directory
sudo userdel -r jan       # delete user and home directory

Managing groups

sudo groupadd developers          # create a group
sudo groupdel developers          # delete a group
sudo gpasswd -d jan developers    # remove jan from the group

To see which groups a user belongs to:

groups jan

Or with GIDs:

id jan

The sudoers file

sudo is configured in /etc/sudoers. Never edit this file directly — use visudo, which validates the syntax before saving. A syntax error in sudoers can lock everyone out of sudo.

sudo visudo

The sudoers syntax:

user  host=(runas)  commands

Give a user full sudo access:

jan  ALL=(ALL:ALL)  ALL

Breaking this down:

  • jan — the user this applies to
  • ALL — from any host
  • (ALL:ALL) — can run as any user and any group
  • ALL — can run any command

Allow a user to run a specific command without a password:

jan  ALL=(ALL)  NOPASSWD: /usr/bin/systemctl restart nginx

Allow a group to have sudo access (the % prefix means group):

%developers  ALL=(ALL:ALL)  ALL

sudoers.d

Rather than editing the main sudoers file, you can drop files into /etc/sudoers.d/. Each file is included automatically.

sudo visudo -f /etc/sudoers.d/jan

This is cleaner for managing per-user or per-application sudo rules.

Switching users

su - jan          # switch to jan (full login shell)
su -              # switch to root (full login shell)
sudo -u jan command   # run a single command as jan
sudo -i           # open a root shell

The - in su - is important. Without it, you switch user but keep the current environment. With it, you get a full login shell with that user's environment.


Most of this happens in the background on a desktop system where you are the only user. On a server with multiple users, shared services, and strict access control, this is the layer that keeps things secure and organised.

Next up: cron and scheduled tasks — automating jobs on a schedule.

0 views