Users and Permissions
Linux's security model is three questions applied to every file: who owns it, what group, and what do the three classes — owner, group, other — get to do? rwxr-xr-- is a contract printed in nine bits. This chapter reads the contract fluently, then goes deeper: the special bits, umask, the password machinery, and sudo's precise delegation of root.
Reading the contract
ls -l file
# -rwxr-xr-- 1 alice devs 4096 Jan 5 file
# ^ the leading char = type: - file, d dir, l symlink, c/b devices
# rwx r-x r-- = owner rwx · group r-x · other r--
r=4, w=2, x=1 — modes as octal: 755 = rwxr-xr-x, 644 = rw-r--r--, 600 = rw-------. On directories x means enterable — a dir with rw but no x is unreadable-inside despite looking writable.
chmod 755 script.sh # octal
chmod u+x script.sh # symbolic — add exec to owner
chmod go-w file # remove write from group+other
chmod -R 644 dir/ # recursive — usually a mistake on dirs+files mixed
chown alice file # change owner
chown alice:devs file # owner + group
chgrp devs file # group only
The special bits — beyond rwx
Three extra bits change behavior fundamentally:
chmod 4755 program # SETUID — runs as the FILE's owner (passwd does this)
chmod 2755 dir # SETGID — runs as group / new files inherit group
chmod 1777 /tmp # STICKY — only owner can delete (why /tmp is shared-safe)
ls -l passwd # -rwsr-xr-x — the 's' marks setuid
setuid is how passwd lets you change your password in a file you don't own — it runs as root. It's also a security hazard — a setuid binary with a bug is privilege escalation waiting. find / -perm -4000 audits them.
umask — the default permissions
New files get 666 & ~umask, dirs 777 & ~umask:
umask # usually 022 → files 644, dirs 755
umask 077 # strict — 600/700, only for you
umask 022 # the sane shared default
Set it in ~/.profile — it's why your files arrive 644 not 777.
The account machinery
id alice # uid, gid, all groups
whoami # effective user
groups # my groups
useradd -m -s /bin/bash alice # create — -m home, -s shell
passwd alice # set her password
usermod -aG wheel alice # add to group — ALWAYS -a or you REPLACE the list
userdel -r alice # remove + home
groupadd devs # new group
gpasswd -d alice devs # remove from group
/etc/passwd — the readable roster: name:x:uid:gid:gecos:home:shell. /etc/shadow — the hashes, root-only: name:$6$hash:... with aging fields. /etc/group — group:x:gid:members. The x in passwd is the shadow split — passwords moved out of the world-readable file long ago.
su vs sudo — two kinds of becoming
su - # become root — LOGIN shell, root's env
su - alice # become alice fully
sudo command # run ONE command as root — logged, delegated
sudo -i # root login via sudo
sudo -u alice cmd # as any user
sudo !! # rerun last command as root — the muscle memory
sudo is configured in /etc/sudoers — edit only with visudo (it syntax-checks before saving; a broken sudoers locks everyone out). The delegation grammar: alice ALL=(ALL) ALL, or %wheel ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx — precise commands, precise users, optionally passwordless. su shares the root password; sudo shares nothing — it logs who ran what.
File ownership inside /proc and friends
A process carries real uid, effective uid, filesystem uid — ls -l /proc/PID/ shows the process's view. Files created follow the effective uid and the process's umask — which is why a daemon's files land with its service user's name on them.
The mode bits — the complete grammar
# symbolic — who, op, what
chmod u+x file # user +execute
chmod g-w file # group -write
chmod o=r file # other =read-only
chmod a+r file # all +read
chmod u+s program # setuid
chmod g+s dir # setgid
chmod +t dir # sticky
chmod u=rwx,g=rx,o= file # combined
# octal — the number language
chmod 644 file # rw- r-- r-- = 6 4 4
chmod 755 file # rwx r-x r-x
chmod 700 dir # rwx --- --- (private)
chmod 600 key # rw- --- --- (keys/secrets)
chmod 640 conf # rw- r-- ---
chmod 664 shared # rw- rw- r--
chmod 2775 sharedir # setgid + 775 — the shared-dir formula
chmod 4755 program # setuid — runs as owner
chmod 1777 /tmp # sticky + world — /tmp's magic
chmod 751 dir # rwx r-x --x — group-traversable, world-blocked
Reading the bits: r=4 w=2 x=1 per triad. find / -perm -4000 finds setuid; find / -perm -0002 world-writable. chmod --reference=other file clones another's mode.
/etc/passwd + shadow + group — the schema
# /etc/passwd — world-readable roster:
# name : x : uid : gid : gecos : home : shell
# alice:x:1000:1000:Alice:/home/alice:/bin/bash
# /etc/shadow — root-only hashes:
# name : $6$salt$hash : lastchange : min : max : warn : inactive : expire
# alice:$6$salt$...:19500:0:99999:7:::
# /etc/group — groups:
# name : x : gid : members
# devs:x:1001:alice,bob
# $6$ = SHA-512 · $y$ = yescrypt · $1$ = MD5 (dead) · $2b$ = bcrypt
vipw/vigr edit passwd/group safely (locking); pwck/grpck sanity-check them. getent passwd alice, getent group devs, getent shadow alice read through NSS (covers LDAP/AD sources too).
The user/group administration surface
useradd -m -s /bin/bash -G wheel,devs alice # -m home -s shell -G groups
useradd -r -s /sbin/nologin svcacct # system account — no login
usermod -aG devs alice # append to groups — ALWAYS -a
usermod -L alice # lock the password
usermod -U alice # unlock it
usermod -s /sbin/nologin alice # kill login without deleting
usermod -d /newhome -m alice # move home
userdel -r alice # remove + home + spool
passwd alice # set password
passwd -l alice # lock the password
chage -l alice # the aging policy
chage -M 90 alice # 90-day max
groupadd devs; gpasswd -a alice devs; gpasswd -d alice devs
newgrp devs # switch primary group live
The classic traps: -G without -a replaces all groups; -r system accounts get low UIDs; /sbin/nologin is a shell that refuses — for service accounts.
su vs sudo — the deep difference
su - # full root login — env, cd ~, everything
su - alice # become alice — her env, her shell
su alice # partial — keeps YOUR env, her identity
su -c 'cmd' alice # one command as alice
sudo cmd # one command as root — your password, logged
sudo -i # root login via sudo
sudo -s # root shell, your env
sudo -u alice cmd # as any user
sudo -l # YOUR allowed commands
sudo -v # validate/refresh the timestamp
sudo -k # kill the timestamp — force re-auth
sudo !! # the classic muscle memory
sudoedit file # edit-as-root without a root-owned file
visudo # THE only way to edit /etc/sudoers
sudo -l shows your delegated rights; visudo syntax-checks before saving (a broken sudoers file locks everyone out). The delegation grammar — alice ALL=(root) /usr/bin/systemctl restart nginx — user, hosts, target-identity, commands. %wheel prefixes groups.
PAM — the auth layer
ls /etc/pam.d/ # per-service policies — login, sshd, sudo...
cat /etc/pam.d/sshd # what sshd auth requires
# auth|account|password|session required|requisite|sufficient|optional module
PAM (Pluggable Authentication Modules) sits under every login — pam_unix (passwords), pam_nologin, pam_securetty, pam_faildelay, pam_faillock (lockout), pam_umask, pam_env. The auth/account/password/session stack order is the policy.
Groups — the shared-access mechanism
A file's group is the primitive for shared access: chgrp devs repo/; chmod g+w repo/ — every devs member can write. Setgid on a directory makes new files inherit the directory's group — the shared-workspace idiom: chmod 2775 repo/ keeps devs ownership propagating downward.
ACLs — when 9 bits aren't enough
setfacl -m u:alice:rw file # alice specifically gets rw
getfacl file # the access-control list
setfacl -m d:u:devs:rwx dir # default ACL — new files inherit
ls -l file # the '+' after the mode = ACLs present
When a file needs different permissions for several specific users — beyond owner/group/other — ACLs carry it. Most systems never need them; the day you do, they're indispensable.
Capabilities — root's powers, unbundled
Traditional root is all-or-nothing; capabilities split it:
setcap 'cap_net_bind_service=+ep' server # bind :80 without root
getcap server
cap_net_bind_service, cap_setuid, cap_sys_admin — the modern way to grant a process one privilege instead of all.
Where permissions go wrong
| Symptom | Cause |
|---|---|
| "Permission denied" on a file you own | Directory missing x — can't traverse |
chmod -R 755 broke ssh keys | ~/.ssh must be 700, keys 600 |
| sudo asks for password constantly | NOPASSWD: absent, or wrong sudoers line |
| usermod wiped group membership | Forgot -a — -G REPLACES |
| New files wrong group | Missing setgid on the shared dir |
find / -perm -4000 surprises | Setuid binaries you didn't expect — audit |
| Script "can't execute" despite 755 | Filesystem mounted noexec — /tmp often is |
Exercises
stata file — read all three timestamps and the mode.umask 077; touch fthenumask 022; touch g— compare.find /usr/bin -perm -4000— inventory the setuid binaries; identify three.- Create a shared dir with setgid; prove new files inherit the group.
visudo-safe edit: grant your userNOPASSWDfor one specific command.- Explain why
passwdneeds setuid — and why it must be bug-free.
See also
- Linux · Filesystem · Processes · Shell