4. users and permissions - mishraxharshit/harshitxmishra.github.io GitHub Wiki
Previous: Phase 3 — Text Processing | Next: Phase 5 — Processes and Services
Linux uses a simple but powerful permission model. Every file and directory has three attributes:
- Owner: one user who owns the file
- Group: one group associated with the file
- Permissions: what the owner, the group, and everyone else can do
Run ls -l to see permissions:
-rwxr-xr-- 1 alice developers 4096 Jan 15 notes.sh
^ | ^ ^
| | | group
| | owner
| number of hard links
permissions
The permissions string has 10 characters:
- r w x r - x r - -
^ ^^^ ^^^ ^^^
| | | |
| | | others (everyone else) permissions
| | group permissions
| owner permissions
file type (- = regular file, d = directory, l = symlink)
Each permission triple is three bits:
-
r— read -
w— write -
x— execute -
-— permission not granted
For files:
-
r— can read the file's content -
w— can modify or delete the file -
x— can run the file as a program
For directories:
-
r— can list the directory's contents withls -
w— can create, delete, or rename files inside the directory -
x— can enter the directory withcdand access files inside (execute on a directory means "traverse")
Permissions are often written as a three-digit number. Each digit represents one of the three groups (owner, group, others) and is the sum of the permission bits:
| Bit | Value | Meaning |
|---|---|---|
| r | 4 | read |
| w | 2 | write |
| x | 1 | execute |
# Numeric mode
chmod 755 script.sh # rwxr-xr-x
chmod 644 notes.txt # rw-r--r--
chmod 600 ~/.ssh/id_rsa # rw------- (required for SSH private keys)
chmod -R 755 /var/www/html # -R applies recursively to all files in directory
Symbolic mode: [who][operation][permission]
who: u=owner, g=group, o=others, a=all
op: + add, - remove, = set exactly
chmod u+x script.sh # add execute for owner
chmod go-w notes.txt # remove write for group and others
chmod a+r public.txt # add read for everyone
chmod u=rw,go=r config.txt # owner: rw, group+others: r
Real-world example: Setting up a web server directory
# Web server user is www-data
# Developer user is alice
Website files: web server reads, developer writes
sudo chown -R alice:www-data /var/www/html
sudo chmod -R 755 /var/www/html
This means: alice can write, www-data (and others) can read and traverse
Configuration files with secrets: only root reads
sudo chmod 600 /etc/mysql/mysql.conf.d/mysqld.cnf
# Change owner
sudo chown bob file.txt
sudo chown bob:developers file.txt # change owner and group
sudo chown :developers file.txt # change only the group
Recursive: change all files in a directory
sudo chown -R alice:alice /home/alice/
Change group only (shorthand with chgrp)
sudo chgrp developers project/
Real-world scenario: A file transferred as root
# You copied a file as root, now you own it
ls -l report.pdf
# -rw-r--r-- 1 root root 45000 Jan 15 report.pdf
Give it back to alice
sudo chown alice:alice report.pdf
Every user has an entry in /etc/passwd. This file is readable by everyone — it does not contain passwords (those are in /etc/shadow).
cat /etc/passwd | head -5
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# alice:x:1000:1000:Alice Smith,,,:/home/alice:/bin/bash
Each field is colon-separated:
- Username
- Password placeholder (
xmeans password is in/etc/shadow) - User ID (UID)
- Primary Group ID (GID)
- GECOS field (full name and other info)
- Home directory
- Default shell
System accounts (daemons like www-data, mysql) have UIDs below 1000 and their shell is /usr/sbin/nologin, meaning they cannot log in interactively.
# Add a new user (creates home directory, default shell)
sudo adduser bob
# Prompts for password and other info
Add user without interactive prompts (for scripts)
sudo useradd -m -s /bin/bash -c "Bob Jones" bob
-m creates home directory
-s sets the shell
-c sets the comment/full name field
Set or change a password
sudo passwd bob
Delete a user
sudo deluser bob
sudo deluser --remove-home bob # also deletes home directory
Modify an existing user
sudo usermod -s /bin/zsh alice # change shell
sudo usermod -aG docker alice # add alice to docker group (-a means append)
sudo usermod -L alice # lock account
sudo usermod -U alice # unlock account
sudo usermod -e 2025-12-31 contractor # set account expiry date
See user information
id alice
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),998(docker)
See who is currently logged in
who
w
last | head -10 # login history
# See all groups
cat /etc/group | grep alice
See groups the current user belongs to
groups
alice sudo docker
Create a group
sudo groupadd developers
Add user to group (takes effect on next login)
sudo usermod -aG developers alice
Remove user from group
sudo gpasswd -d alice developers
Delete a group
sudo groupdel developers
The root user has UID 0 and bypasses all permission checks. Running everything as root is dangerous: a single typo like rm -rf /tmp /important (note the accidental space) can destroy the system.
sudo (superuser do) lets authorised users run individual commands as root. It logs every action, requires the user's own password, and can be restricted to specific commands.
# Run a single command as root
sudo apt update
Open a root shell (be careful, stay in it only for what you need)
sudo bash
or
sudo su -
Run a command as a different user
sudo -u www-data ls /var/www/html
See what sudo commands you are allowed to run
sudo -l
sudo configuration is in /etc/sudoers. Edit it with visudo, which validates syntax before saving (a broken sudoers file can lock you out).
sudo visudo
Common sudoers entries:
Give alice full sudo access (same as root)
alice ALL=(ALL:ALL) ALL
Allow alice to run apt without a password
alice ALL=(ALL) NOPASSWD: /usr/bin/apt
Give the developers group full access
%developers ALL=(ALL:ALL) ALL
Password authentication is convenient but less secure. SSH keys use asymmetric cryptography: a private key (never shared) and a public key (placed on the server).
# Generate an SSH key pair
ssh-keygen -t ed25519 -C "alice@mycomputer"
# Creates:
# ~/.ssh/id_ed25519 (private key — never share this)
# ~/.ssh/id_ed25519.pub (public key — place this on servers)
Copy public key to a remote server
ssh-copy-id [email protected]
This adds your public key to ~/.ssh/authorized_keys on the server
Connect using the key (no password prompt if configured correctly)
If you have multiple keys, specify which one
ssh -i ~/.ssh/work_key [email protected]
Required permissions for SSH keys (SSH refuses to use keys with wrong permissions)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
Beyond the standard rwx bits, there are three special bits.
Setuid (SUID): When set on an executable, the program runs with the file owner's permissions rather than the executing user's permissions. The passwd command uses this: it runs as root so it can write to /etc/shadow, even when run by a regular user.
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 /usr/bin/passwd
# ^ the 's' in owner execute position means setuid is set
Setgid (SGID): On an executable, runs with the file group's permissions. On a directory, new files created inside inherit the directory's group rather than the creator's primary group. Useful for shared project directories.
chmod g+s /shared/project
# Files created inside inherit project's group
Sticky bit: On a directory, only the file's owner (or root) can delete the file, even if others have write permission on the directory. Used on /tmp so users cannot delete each other's temporary files.
ls -ld /tmp
# drwxrwxrwt 20 root root 4096 Jan 15 /tmp
# ^ the 't' in others execute position means sticky bit is set
chmod +t /shared/uploads
Exercise 1: Create a file called test.txt. Use ls -l to see its permissions. Use chmod to change permissions to 640. Verify with ls -l. Explain what 640 means.
Exercise 2: Create a directory called shared. Set permissions so the owner can read/write/execute, the group can read and execute, and others have no access. What numeric permission is this?
Exercise 3: Look up your own UID and GID using id. Then look at your entry in /etc/passwd. What is your default shell?
Exercise 4: Run ls -la /usr/bin/sudo and /usr/bin/passwd. Note the special permission bits. Explain why each one needs the permissions it has.
Exercise 5: Generate an SSH key pair with ssh-keygen. Verify that the private key has permissions 600 and the public key has permissions 644.
Mistake: Setting 777 permissions
chmod 777 gives everyone full access. This is almost never correct. If you find yourself doing this to "fix a permission error", stop and understand why the error is occurring.
Mistake: Logging in as root for daily work
Use your regular user account and sudo only when required. If you damage something as root, there is no safety net.
Mistake: Forgetting that group membership changes need re-login
If you add a user to a group with usermod -aG, the user must log out and back in (or run newgrp groupname) for the change to take effect in their shell session.
Mistake: Keeping SSH private keys unprotected
Your private key at ~/.ssh/id_ed25519 must have permissions 600. If it is world-readable, SSH will refuse to use it and print an error about "unprotected private key file".
Previous: Phase 3 — Text Processing | Next: Phase 5 — Processes and Services
# Phase 4 — Users and PermissionsPrevious: [Phase 3 — Text Processing](Phase-3-Text-Processing) | Next: [Phase 5 — Processes and Services](Phase-5-Processes-and-Services)
Linux uses a simple but powerful permission model. Every file and directory has three attributes:
- Owner: one user who owns the file
- Group: one group associated with the file
- Permissions: what the owner, the group, and everyone else can do
Run ls -l to see permissions:
-rwxr-xr-- 1 alice developers 4096 Jan 15 notes.sh
^ | ^ ^
| | | group
| | owner
| number of hard links
permissions
The permissions string has 10 characters:
- r w x r - x r - -
^ ^^^ ^^^ ^^^
| | | |
| | | others (everyone else) permissions
| | group permissions
| owner permissions
file type (- = regular file, d = directory, l = symlink)
Each permission triple is three bits:
-
r— read -
w— write -
x— execute -
-— permission not granted
For files:
-
r— can read the file's content -
w— can modify or delete the file -
x— can run the file as a program
For directories:
-
r— can list the directory's contents withls -
w— can create, delete, or rename files inside the directory -
x— can enter the directory withcdand access files inside (execute on a directory means "traverse")
Permissions are often written as a three-digit number. Each digit represents one of the three groups (owner, group, others) and is the sum of the permission bits:
| Bit | Value | Meaning |
|---|---|---|
| r | 4 | read |
| w | 2 | write |
| x | 1 | execute |
So:
-
rwx= 4+2+1 = 7 -
rw-= 4+2+0 = 6 -
r-x= 4+0+1 = 5 -
r--= 4+0+0 = 4 -
---= 0+0+0 = 0
Common permission combinations:
| Number | String | Typical Use |
|---|---|---|
| 755 | rwxr-xr-x | Executable program, public website directory |
| 644 | rw-r--r-- | Regular text file, configuration file |
| 700 | rwx------ | Personal script only you can run |
| 600 | rw------- | Private key, password file |
| 777 | rwxrwxrwx | Avoid: gives everyone full access |
| 000 | --------- | No one can access (even owner, unless root) |
# Numeric mode
chmod 755 script.sh # rwxr-xr-x
chmod 644 notes.txt # rw-r--r--
chmod 600 ~/.ssh/id_rsa # rw------- (required for SSH private keys)
chmod -R 755 /var/www/html # -R applies recursively to all files in directory
# Symbolic mode: [who][operation][permission]
# who: u=owner, g=group, o=others, a=all
# op: + add, - remove, = set exactly
chmod u+x script.sh # add execute for owner
chmod go-w notes.txt # remove write for group and others
chmod a+r public.txt # add read for everyone
chmod u=rw,go=r config.txt # owner: rw, group+others: rReal-world example: Setting up a web server directory
# Web server user is www-data
# Developer user is alice
# Website files: web server reads, developer writes
sudo chown -R alice:www-data /var/www/html
sudo chmod -R 755 /var/www/html
# This means: alice can write, www-data (and others) can read and traverse
# Configuration files with secrets: only root reads
sudo chmod 600 /etc/mysql/mysql.conf.d/mysqld.cnf# Change owner
sudo chown bob file.txt
sudo chown bob:developers file.txt # change owner and group
sudo chown :developers file.txt # change only the group
# Recursive: change all files in a directory
sudo chown -R alice:alice /home/alice/
# Change group only (shorthand with chgrp)
sudo chgrp developers project/Real-world scenario: A file transferred as root
# You copied a file as root, now you own it
ls -l report.pdf
# -rw-r--r-- 1 root root 45000 Jan 15 report.pdf
# Give it back to alice
sudo chown alice:alice report.pdfEvery user has an entry in /etc/passwd. This file is readable by everyone — it does not contain passwords (those are in /etc/shadow).
cat /etc/passwd | head -5
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# alice:x:1000:1000:Alice Smith,,,:/home/alice:/bin/bashEach field is colon-separated:
- Username
- Password placeholder (
xmeans password is in/etc/shadow) - User ID (UID)
- Primary Group ID (GID)
- GECOS field (full name and other info)
- Home directory
- Default shell
System accounts (daemons like www-data, mysql) have UIDs below 1000 and their shell is /usr/sbin/nologin, meaning they cannot log in interactively.
# Add a new user (creates home directory, default shell)
sudo adduser bob
# Prompts for password and other info
# Add user without interactive prompts (for scripts)
sudo useradd -m -s /bin/bash -c "Bob Jones" bob
# -m creates home directory
# -s sets the shell
# -c sets the comment/full name field
# Set or change a password
sudo passwd bob
# Delete a user
sudo deluser bob
sudo deluser --remove-home bob # also deletes home directory
# Modify an existing user
sudo usermod -s /bin/zsh alice # change shell
sudo usermod -aG docker alice # add alice to docker group (-a means append)
sudo usermod -L alice # lock account
sudo usermod -U alice # unlock account
sudo usermod -e 2025-12-31 contractor # set account expiry date
# See user information
id alice
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),998(docker)
# See who is currently logged in
who
w
last | head -10 # login history# See all groups
cat /etc/group | grep alice
# See groups the current user belongs to
groups
# alice sudo docker
# Create a group
sudo groupadd developers
# Add user to group (takes effect on next login)
sudo usermod -aG developers alice
# Remove user from group
sudo gpasswd -d alice developers
# Delete a group
sudo groupdel developersThe root user has UID 0 and bypasses all permission checks. Running everything as root is dangerous: a single typo like rm -rf /tmp /important (note the accidental space) can destroy the system.
sudo (superuser do) lets authorised users run individual commands as root. It logs every action, requires the user's own password, and can be restricted to specific commands.
# Run a single command as root
sudo apt update
# Open a root shell (be careful, stay in it only for what you need)
sudo bash
# or
sudo su -
# Run a command as a different user
sudo -u www-data ls /var/www/html
# See what sudo commands you are allowed to run
sudo -lsudo configuration is in /etc/sudoers. Edit it with visudo, which validates syntax before saving (a broken sudoers file can lock you out).
sudo visudo
# Common sudoers entries:
# Give alice full sudo access (same as root)
alice ALL=(ALL:ALL) ALL
# Allow alice to run apt without a password
alice ALL=(ALL) NOPASSWD: /usr/bin/apt
# Give the developers group full access
%developers ALL=(ALL:ALL) ALLPassword authentication is convenient but less secure. SSH keys use asymmetric cryptography: a private key (never shared) and a public key (placed on the server).
# Generate an SSH key pair
ssh-keygen -t ed25519 -C "alice@mycomputer"
# Creates:
# ~/.ssh/id_ed25519 (private key — never share this)
# ~/.ssh/id_ed25519.pub (public key — place this on servers)
# Copy public key to a remote server
ssh-copy-id [email protected]
# This adds your public key to ~/.ssh/authorized_keys on the server
# Connect using the key (no password prompt if configured correctly)
ssh [email protected]
# If you have multiple keys, specify which one
ssh -i ~/.ssh/work_key [email protected]
# Required permissions for SSH keys (SSH refuses to use keys with wrong permissions)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keysBeyond the standard rwx bits, there are three special bits.
Setuid (SUID): When set on an executable, the program runs with the file owner's permissions rather than the executing user's permissions. The passwd command uses this: it runs as root so it can write to /etc/shadow, even when run by a regular user.
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 /usr/bin/passwd
# ^ the 's' in owner execute position means setuid is setSetgid (SGID): On an executable, runs with the file group's permissions. On a directory, new files created inside inherit the directory's group rather than the creator's primary group. Useful for shared project directories.
chmod g+s /shared/project
# Files created inside inherit project's groupSticky bit: On a directory, only the file's owner (or root) can delete the file, even if others have write permission on the directory. Used on /tmp so users cannot delete each other's temporary files.
ls -ld /tmp
# drwxrwxrwt 20 root root 4096 Jan 15 /tmp
# ^ the 't' in others execute position means sticky bit is set
chmod +t /shared/uploadsExercise 1: Create a file called test.txt. Use ls -l to see its permissions. Use chmod to change permissions to 640. Verify with ls -l. Explain what 640 means.
Exercise 2: Create a directory called shared. Set permissions so the owner can read/write/execute, the group can read and execute, and others have no access. What numeric permission is this?
Exercise 3: Look up your own UID and GID using id. Then look at your entry in /etc/passwd. What is your default shell?
Exercise 4: Run ls -la /usr/bin/sudo and /usr/bin/passwd. Note the special permission bits. Explain why each one needs the permissions it has.
Exercise 5: Generate an SSH key pair with ssh-keygen. Verify that the private key has permissions 600 and the public key has permissions 644.
Mistake: Setting 777 permissions
chmod 777 gives everyone full access. This is almost never correct. If you find yourself doing this to "fix a permission error", stop and understand why the error is occurring.
Mistake: Logging in as root for daily work
Use your regular user account and sudo only when required. If you damage something as root, there is no safety net.
Mistake: Forgetting that group membership changes need re-login
If you add a user to a group with usermod -aG, the user must log out and back in (or run newgrp groupname) for the change to take effect in their shell session.
Mistake: Keeping SSH private keys unprotected
Your private key at ~/.ssh/id_ed25519 must have permissions 600. If it is world-readable, SSH will refuse to use it and print an error about "unprotected private key file".
Previous: [Phase 3 — Text Processing](Phase-3-Text-Processing) | Next: [Phase 5 — Processes and Services](Phase-5-Processes-and-Services)