Users#
Identity is where every operation begins. The operator lands on a box
as some UID with some primary GID and a supplementary group list, and
that triple decides what the next syscall is allowed to do. Reading
the identity layer fast (id, whoami, getent, groups)
is the first move on an unfamiliar host, friendly or hostile.
The model is POSIX-defined (<sys/types.h> defines uid_t and
gid_t), so the same enumeration tradecraft holds on Linux, BSD,
and macOS. Every file-access check, every setuid transition,
every kernel permission gate runs against this triple, and so does
every privilege-escalation finding the operator writes up.
┌────────────────────────── Process Identity ──────────────────────────┐
│ │
│ UID ──────────► who am I (owner of the process) │
│ │
│ GID ──────────► primary group (default group on new files)│
│ │
│ Groups ──────► supplementary list (member of: sudo, docker, │
│ users, wheel, video, ...) │
│ │
└──────────────────────────────────────────────────────────────────────┘
│
│ kernel checks against
▼
┌────────────────────────────────────────────────────────────────────────┐
│ File: -rw-r----- operator staff secrets.txt │
│ │ │ │ │ │ │
│ │ │ │ │ └─ group → must be in supplementary │
│ │ │ │ └───────── owner → must match UID │
│ │ │ └────────────── others → fallback │
│ │ └────────────────── group bits │
│ └────────────────────── owner bits │
└────────────────────────────────────────────────────────────────────────┘
Home#
Each user has a home directory ($HOME, configured in
/etc/passwd, abbreviated as ~). The convention is
/home/USER for regular users and /root for root. Personal
config lives there as dotfiles (filenames starting with .,
hidden from ls by default). Newer applications follow the
XDG Base Directory layout, which separates config, cache, data,
and state into their own paths.
Path |
Environment variable |
Purpose |
|---|---|---|
|
(none) |
Classic dotfiles for shell, SSH, GnuPG (per-app conventions) |
|
|
User config (preferences, profiles) |
|
|
Disposable cached data; safe to delete |
|
|
Persistent app data (databases, history) |
|
|
Runtime state (logs, undo files, lockfiles) |
|
(none) |
Per-user executables on |
whoami prints just your username:
$ whoami
operator
$HOME is the absolute path to your home directory:
$ echo $HOME
/home/operator
id prints the full identity (UID, primary GID, supplementary
groups):
$ id
uid=1000(operator) gid=1000(operator) groups=1000(operator),27(sudo),100(users)
List the dotfiles in $HOME:
$ ls -la ~
drwx------ 5 operator operator 4096 May 1 09:14 .
drwxr-xr-x 3 root root 4096 Apr 28 17:02 ..
-rw------- 1 operator operator 220 Apr 28 17:02 .bashrc
drwx------ 2 operator operator 4096 Apr 28 17:05 .ssh
Shells#
A user’s login shell is the program init execs after
authentication, recorded as the last field of the entry in
/etc/passwd. Available shells are listed in /etc/shells,
and chsh rewrites the entry for the current user.
$SHELL holds the path of your login shell:
$ echo $SHELL
/bin/bash
List every shell installed on the system:
$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/zsh
/usr/bin/fish
A line in /etc/passwd is seven colon-separated fields. Knowing
each field on sight saves time when reading getent passwd output
or auditing a foreign system.
$ cat /etc/passwd
operator:x:1000:1000:Operator:/home/operator:/bin/bash
/etc/passwd line format:
operator : x : 1000 : 1000 : Operator,,, : /home/operator : /bin/bash
│ │ │ │ │ │ │
│ │ │ │ │ │ └─ login shell
│ │ │ │ │ └─ home directory
│ │ │ │ └─ GECOS comment (full name etc.)
│ │ │ └─ primary GID
│ │ └─ UID (0 = root, <1000 = system, ≥1000 = real)
│ └─ password placeholder ('x' = look in /etc/shadow)
└─ login name
getent queries the system databases (passwd, group,
hosts); useful when entries come from LDAP or SSSD, not just
/etc/passwd:
$ getent passwd $USER
operator:x:1000:1000:Operator:/home/operator:/bin/bash
chsh -s rewrites the login-shell field of /etc/passwd:
$ chsh -s /usr/bin/zsh
Password:
(no further output; takes effect at next login)
Groups#
A user belongs to one primary group and zero or more
supplementary groups. Group membership controls file access and
which privileged devices or services you can use without sudo:
members of docker get the Docker socket, members of
wireshark can capture packets, and so on.
groups lists the group names you belong to:
$ groups
operator sudo users
id -Gn prints the same list using id; useful in scripts:
$ id -Gn
operator sudo users
Look up who is in a given group:
$ getent group sudo
sudo:x:27:operator,alice
usermod -aG adds a user to a supplementary group; the change
takes effect on the next login (or via newgrp):
$ sudo usermod -aG docker operator
(no output; check with ``id`` after re-login)
Switch#
su switches to another user. su - (with the dash) starts a
fresh login shell that re-reads the new user’s profile, environment,
and $PATH; plain su USER keeps the current shell’s
environment, which is usually not what you want for an admin task.
Become root with a full login shell:
$ su -
Password:
root@system:~#
Become another regular user with their environment:
$ su - operator
Password:
operator@system:~$
Switch to a service account while keeping your current shell environment:
$ su postgres
postgres@system:/home/operator$
Sudo#
sudo is the controlled way to run a single command as root (or
another user) while keeping an audit trail of who ran what and when.
Privileges are governed by /etc/sudoers and drop-ins under
/etc/sudoers.d/, edited only with visudo.
The decision tree below is what the operator should run through
when they need elevated privilege. su and sudo answer
different questions; picking the wrong one produces audit gaps,
lost env vars, or denied access.
flowchart LR
Q(["Need to run a command<br/>as another user"])
Q -->|"as root, audited"| A1["sudo CMD"]
Q -->|"as root, interactive shell"| A2["sudo -i (clean env)<br/>sudo -s (current env)"]
Q -->|"as some other user, one cmd"| A3["sudo -u USER CMD"]
Q -->|"what am I allowed to do"| A4["sudo -l"]
Q -->|"edit sudoers safely"| A5["sudo visudo<br/>sudo visudo -c (validate)"]
Q -->|"service account, have password"| A6["su - USER"]
Q -->|"full root login shell, no sudo"| A7["su -"]
Form |
Effect |
|---|---|
|
Run command as root |
|
Open an interactive root shell |
|
Run command as another user |
|
List what you’re allowed to run |
|
Safely edit |
Run a single command as root; only root can read /etc/shadow:
$ sudo cat /etc/shadow
[sudo] password for operator:
root:$6$...:19234:0:99999:7:::
...
Open an interactive root shell:
$ sudo -i
root@system:~#
Run a command as a non-root user (e.g. open a Postgres shell as
the postgres user):
$ sudo -u postgres psql
psql (16.1)
Type "help" for help.
postgres=#
List what your account is allowed to run with sudo:
$ sudo -l
User operator may run the following commands on system:
(ALL : ALL) ALL
Common Tasks#
Enumerate accounts (real users, system users, service accounts).
$ getent passwd
$ awk -F: '$3>=1000 && $1!="nobody"{print $1}' /etc/passwd
$ awk -F: '$7~/(bash|zsh|sh|fish)$/{print $1,$7}' /etc/passwd
Audit privileged access (who is in the wheel/sudo/admin set, who has root).
$ getent group sudo wheel admin
$ sudo cat /etc/sudoers
$ sudo ls -la /etc/sudoers.d/
$ sudo grep -rE 'NOPASSWD|ALL=' /etc/sudoers /etc/sudoers.d/ 2>/dev/null
Login history (who has touched the box).
$ last -F | head -30
$ lastlog | awk '$2!="**Never"'
$ sudo journalctl _COMM=sshd | tail -50
$ who; w
Password / lock state (which accounts can authenticate).
$ sudo passwd -S -a
$ sudo awk -F: '$2!~/^[!*]/{print $1}' /etc/shadow
$ sudo chage -l <user>
Hunt persistence (new accounts, weird shells, suspect home dirs).
$ sort /etc/passwd | awk -F: '{print $1,$3,$7}' | sort -k2 -n
$ find /home /root -maxdepth 3 -name '.ssh' -exec ls -la {} \;
$ awk -F: '$3==0{print $1}' /etc/passwd
Add / disable a user safely (for cleanup or for an authorized test account).
$ sudo useradd -m -s /bin/bash -G sudo opuser
$ sudo passwd opuser
$ sudo usermod -L baduser
$ sudo userdel -r baduser
Switch identities (run as another user, drop into root).
$ sudo -i # full root login shell
$ sudo -u www-data -s # shell as a service user
$ su - <user>
$ id; whoami; groups
Manage groups (add, remove, change membership).
$ getent group <group>
$ sudo groupadd ops
$ sudo usermod -aG sudo,ops <user> # -aG, never plain -G
$ sudo gpasswd -d <user> <group>
Set or expire a password (including force-change on next login).
$ sudo passwd <user>
$ sudo passwd -e <user> # expire now
$ sudo chage -M 90 -m 7 -W 14 <user> # aging policy
See active sessions (who is logged in right now).
$ who; w; users
$ loginctl list-sessions
$ ps -eo user,tty,pid,cmd | grep -v '^root'
Edit sudoers safely (syntax-checked).
$ sudo visudo
$ sudo visudo -f /etc/sudoers.d/ops
$ sudo visudo -c # validate without editing
References#
man 5 passwd,man 5 shadow,man 5 group(account database file formats).man 5 sudoers,man 8 sudo,man 8 visudo(sudo policy and editor).man 1 id,man 1 whoami,man 1 groups,man 1 getent(identity lookup).man 1 su,man 1 chsh,man 8 useradd,man 8 usermod,man 8 userdel,man 1 passwd,man 1 chage(account management).Permissions for the permission, sudoers, and capability layer that consumes this identity.
Shells for per-shell coverage and login behavior.
Linux for the command quick-reference.