LFCA 22 ๐ง Viewing Users and Groups โ /etc/passwd, /etc/group
The previous chapter explained what users and groups are. This chapter is about seeing them. Every identity on a Linux system is recorded in plain text files, and reading those files directly is the fastest way to answer questions like “what UID does this user have?”, “who is in the sudo group?”, “what shell does the web server use?”, or “are there any accounts with UID 0 besides root?” The tools that display this information โ cat, grep, awk, getent, id, groups, who, w, last, lastlog โ are simple, and they are the ones you will reach for when a permission problem needs diagnosing or a security review needs doing. This chapter covers the format of /etc/passwd, /etc/group, /etc/shadow, and /etc/gshadow, the commands that display them, the query tools that read from the system’s configured identity source rather than the files directly, and the patterns for common inspection tasks. It does not cover creating or modifying users โ those are separate chapters.
Key point: /etc/passwd and /etc/group are the canonical files, but they are not always the only source of identity. On systems configured with LDAP, SSSD, or systemd-homed, users may exist in a directory service rather than in the local files. getent queries the system’s full identity source, while cat /etc/passwd reads only the local file. For reliable inspection on any system, getent is preferred. For raw structural inspection, the files themselves are the reference.
The format of /etc/passwd
Each line in /etc/passwd describes one user account and has seven colon-separated fields.
alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
The fields are, in order: the username, the password placeholder (usually x), the UID, the primary GID, the comment field (GECOS, often the full name), the home directory, and the login shell. The colon is the separator, and no field may contain a colon โ that is why the comment field is limited and why paths with colons are unusual.
Why the password field is x. The password hash was moved out of /etc/passwd into /etc/shadow for security, because /etc/passwd must be world-readable and a readable hash is a cracking target. The x is a marker telling the system “the hash is in /etc/shadow, look it up by username.” On some very old or very minimal systems the field still contains the hash โ or is empty, meaning no password is required. On a modern Linux system it is x.
Why the fields are position-sensitive. The format is not self-describing. There is no header, no field names, no schema. The order is fixed and every tool that reads the file relies on that order. A malformed line โ one with the wrong number of fields or a stray colon โ can cause login failures or misidentify the account. This is one reason editing /etc/passwd by hand is discouraged and tools like useradd exist.
Why system accounts live in the same file. There is no separate file for system accounts. They are entries in /etc/passwd with UIDs below 1000 and, typically, a shell of /usr/sbin/nologin or /bin/false. www-data, sshd, systemd-network, and dozens of others appear alongside human accounts. Reading the file means reading both, and the UID range is the way to tell them apart.
Why the home directory and shell can be unusual. For system accounts, the home directory is often / or /nonexistent and the shell is a nologin variant. For human accounts, the home is under /home and the shell is a real shell. The home directory can technically be anywhere; the shell can be any program, including a custom one. The file records whatever the administrator configured.
Why
/etc/passwdcan be read by anyone. Every process that needs to translate a UID into a name consults this file.ls -l,ps aux,top,htop, and dozens of others display usernames, and they can be run by any user. If the file were restricted, these tools would show numbers instead of names for unprivileged users. Making it world-readable is a deliberate tradeoff: the names and UIDs are not considered secret, only the hashes are.
The format of /etc/group
Each line in /etc/group describes one group and has four colon-separated fields.
developers:x:1001:alice,bob,carol
The fields are: the group name, the password placeholder (usually x), the GID, and the member list โ a comma-separated list of usernames with no spaces.
Why the member list does not include everyone. A user’s primary group is recorded in /etc/passwd, not in /etc/group. So a user whose primary group is their own name (the standard on most distributions) does not appear in any member list for that group. The member list holds only the supplementary members. To find all members of a group, you need to check both the member list in /etc/group and the primary GID in /etc/passwd.
Why the group password field exists. Groups can technically have passwords โ a way to join a group temporarily with newgrp โ but the feature is almost never used and the field is nearly always x or empty. The password hashes, when present, are in /etc/gshadow, which serves the same role for groups that /etc/shadow serves for users.
Why an empty member list is common. Many groups exist only to own files. A group created for a service โ docker, www-data, systemd-journal โ may have no supplementary members at all. Its purpose is to be the group owner of certain files or to be a primary group for a service account. An empty member list does not mean the group is unused.
Why the GID matters more than the name. Like UIDs, GIDs are the numbers the kernel uses. Two different systems can have groups with the same name but different GIDs, which matters when files are shared across systems. The ls -ln output shows the GID; getent group translates it back to a name.
The shadow files
/etc/shadow holds password hashes and password aging policy for users. /etc/gshadow holds the equivalent for groups. Both are readable only by root.
/etc/shadow format. Nine colon-separated fields: username, password hash, last password change (days since epoch), minimum days before change allowed, maximum days before change required, warning days before expiry, inactivity days after expiry before account is disabled, account expiration date (days since epoch), and a reserved field. The hash is the sensitive part; the aging fields are policy.
alice:$6$rounds=5000$xyz...:19000:0:99999:7:::
The $6$ prefix indicates SHA-512. Other prefixes include $1$ (MD5, obsolete), $5$ (SHA-256), and $y$ (yescrypt, modern default on some distributions). The hash format tells you which algorithm was used, which is useful for auditing โ a system still using $1$ hashes should be migrated.
Why the aging fields matter. The last-change, min, max, warn, and inactivity fields enforce password policy. A max of 99999 means the password never expires. A max of 90 means it must be changed every 90 days. The inactivity field disables the account after the password expires and the user fails to change it within the grace period. These fields are set by chage and consulted by the login program.
/etc/gshadow format. Four colon-separated fields: group name, password hash, group administrators, and group members. It is rarely inspected but can reveal which groups have administrators or unusual membership. On most systems it mirrors /etc/group with ! or empty in the password field.
Why shadow files are root-only. A password hash is not the password, but it is close enough. An attacker with a hash can attempt offline cracking โ trying billions of candidate passwords against the hash without touching the system. Restricting the file to root removes that opportunity. The check is enforced by file permissions: /etc/shadow is typically 640 with owner root and group shadow, so only root and members of the shadow group can read it.
Why
chage -lis the safe way to read shadow data. Thechage -l alicecommand prints the password aging information for a user in a readable format. It requires root for another user’s data but avoids direct parsing of/etc/shadow.chageis the tool designed for the job, and it handles the edge cases of missing or unusual entries.
Reading the files with text tools
The files are plain text, so cat, grep, awk, and cut all work. For quick inspection, they are often faster than a dedicated tool.
# Print the whole file
cat /etc/passwd
# Find a user
grep alice /etc/passwd
# Find a group
grep developers /etc/group
# List just usernames
cut -d: -f1 /etc/passwd
# List UIDs and usernames
awk -F: '{ print $3, $1 }' /etc/passwd
# List system accounts (UID < 1000)
awk -F: '$3 < 1000 { print $1, $3 }' /etc/passwd
# List regular users (UID >= 1000)
awk -F: '$3 >= 1000 && $3 < 65534 { print $1, $3 }' /etc/passwd
# Find accounts with a real shell
grep -v -E '/nologin|/false' /etc/passwd
# Find members of a group
grep sudo /etc/group
Why awk -F: is the standard tool. The -F: sets the field separator to colon, and then $1, $3, and so on refer to the fields. This is the cleanest way to extract specific columns from the identity files. The pattern '$3 < 1000 { print $1 }' reads as “when the third field is less than 1000, print the first field” โ a direct expression of the query.
Why cut -d: -f1 is sometimes enough. When you only need one field and no filtering, cut is simpler than awk. cut -d: -f1 /etc/passwd prints the first field of every line, which is the list of usernames. cut cannot filter by value, so for conditional queries awk is the tool.
Why grep -v is useful for finding real users. System accounts have nologin or false as their shell. Excluding those lines leaves the accounts that can actually log in. This is a fast way to answer “how many human users does this system have?” without needing to know the UID convention.
Why direct file reading has limits. On a system configured with LDAP, SSSD, or NIS, /etc/passwd contains only the local accounts. A user who exists in the directory service does not appear in the file, and grep alice /etc/passwd returns nothing even though id alice succeeds. This is the gap that getent fills.
Why the files are the reference but not always the truth. The files are the local identity database. They are authoritative for local accounts. But the system’s view of “who exists” may include remote identities. When inspecting a system, it is worth knowing whether it is standalone or directory-connected. On a standalone system, the files and
getentagree. On a connected system, they do not, andgetentis the one that shows what the system actually sees.
getent โ the query tool
getent reads from the system’s configured name service switch (NSS) sources, not just the files. On a standalone system, it reads /etc/passwd, /etc/group, and the other files. On a connected system, it also queries LDAP, SSSD, or NIS. For any query about identity, getent is the tool that gives the answer the system will act on.
# Look up a user by name
getent passwd alice
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
# Look up a user by UID
getent passwd 1000
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
# List all users the system knows
getent passwd
# Look up a group by name
getent group developers
# developers:x:1001:alice,bob,carol
# Look up a group by GID
getent group 1001
# developers:x:1001:alice,bob,carol
# Look up shadow data (requires root)
sudo getent shadow alice
Why getent is preferred over cat. The two produce the same output on a standalone system. On a directory-connected system, getent includes remote identities and cat does not. When debugging “the user should exist but the system says no,” getent tells you what the system actually resolves. When debugging “the file says the user exists but login fails,” getent reveals whether the name service is returning the entry.
Why the database name is the first argument. getent passwd, getent group, getent shadow, getent hosts, getent services โ each queries a different NSS database. The name matches the file name in /etc for the local source, but the database can be backed by anything the name service switch is configured to consult.
Why getent passwd with no argument lists everything. Unlike grep, which reads only the file, getent passwd with no lookup key enumerates every entry the system knows about, across all configured sources. This is the complete list of identities, and it is what a script should iterate over when it needs “all users” rather than “all local users.”
Why getent can be slower than cat. On a system connected to a directory service, getent passwd may issue network requests. On a large directory, the full enumeration can take seconds. For a single lookup by name or UID, getent is fast because the directory is indexed. For a full enumeration, cat /etc/passwd is faster but incomplete.
Viewing the current session
The identity files describe who exists. The session tools describe who is currently logged in and what they are doing.
# Who is logged in
who
# alice pts/0 2026-03-15 10:22 (192.168.1.10)
# bob pts/1 2026-03-15 10:45 (192.168.1.11)
# More detail, including idle time and current command
w
# 10:50:12 up 3 days, 2 users, load average: 0.15, 0.10, 0.05
# USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
# alice pts/0 192.168.1.10 10:22 0.00s 0.15s 0.02s w
# bob pts/1 192.168.1.11 10:45 5:00 0.10s 0.05s vim notes.txt
# The current user's identity
id
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1001(developers)
# The current user's name only
whoami
# alice
Why who and w differ. who prints the login sessions โ one line per session, with the user, terminal, login time, and source address. w adds the system uptime, load average, and per-user idle time and current command. w is the richer view; who is the minimal one.
Why the FROM column matters. For remote logins, FROM shows the originating IP address or hostname. This is the first thing to check in a security review โ an unexpected source address means an unexpected login. For local logins, the column is empty or shows :0 (the local display).
Why id and whoami are still needed. who and w list all sessions. id and whoami answer “who am I right now?” โ which is essential when you have used sudo, su, or ssh and need to confirm which identity the current shell carries.
Viewing login history
The files /var/log/wtmp, /var/log/btmp, and /var/log/lastlog record login and logout events. The last, lastb, and lastlog commands read them.
# Recent successful logins
last
# alice pts/0 192.168.1.10 Sat Mar 15 10:22 still logged in
# bob pts/1 192.168.1.11 Sat Mar 15 10:45 still logged in
# alice pts/0 192.168.1.10 Fri Mar 14 09:15 - 17:30 (08:15)
# Recent failed logins (requires root on some systems)
sudo lastb
# root ssh:notty 203.0.113.5 Sat Mar 15 03:12 - 03:12 (00:00)
# admin ssh:notty 203.0.113.5 Sat Mar 15 03:13 - 03:13 (00:00)
# Last login for each user
lastlog
# Username Port From Latest
# root **Never logged in**
# daemon **Never logged in**
# alice pts/0 192.168.1.10 Sat Mar 15 10:22:14 +0000 2026
# bob pts/1 192.168.1.11 Sat Mar 15 10:45:01 +0000 2026
Why last is the first tool in an incident review. It shows when each user logged in, from where, and for how long. A login from an unexpected IP address, or at an unexpected time, is a red flag. The “still logged in” marker shows active sessions.
Why lastb requires care. Failed logins are recorded in /var/log/btmp, which is readable only by root on most systems. Repeated failed logins from the same IP address suggest a brute-force attempt. The command to read it is lastb, and it is the mirror of last for failures.
Why lastlog is useful for account auditing. It shows the last login time for every account, including the ones that have never logged in. System accounts with **Never logged in** are expected. A human account that has never logged in, or has not logged in for months, is a candidate for review or removal.
Why these logs rotate. The wtmp, btmp, and lastlog files grow continuously and are rotated by logrotate. The rotation policy determines how far back the history goes. On a busy system, the history may cover only days; on a quiet one, months. The last command reports what is in the current file plus any archived rotations that are still present.
Why the login history is not the full picture.
lastrecords logins through the normal login mechanism โlogin,sshd,su, and similar. It does not record everysudoinvocation (that is in/var/log/auth.logor the journal) and it does not record commands run within a session. For a full audit trail,lastis the starting point, and the auth log is the next place to look.
Complete Example Session
# ============================================
# PART 1: READ /etc/passwd
# ============================================
head -5 /etc/passwd
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# bin:x:2:2:bin:/bin:/usr/sbin/nologin
# sys:x:3:3:sys:/dev:/usr/sbin/nologin
# sync:x:4:65534:sync:/bin:/bin/sync
grep alice /etc/passwd
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
# ============================================
# PART 2: EXTRACT FIELDS
# ============================================
cut -d: -f1 /etc/passwd | head -5
# root
# daemon
# bin
# sys
# sync
awk -F: '{ print $3, $1 }' /etc/passwd | sort -n | tail -3
# 1000 alice
# 1001 bob
# 1002 carol
# ============================================
# PART 3: FILTER BY UID RANGE
# ============================================
# System accounts
awk -F: '$3 < 1000 { print $1, $3 }' /etc/passwd | head -5
# root 0
# daemon 1
# bin 2
# sys 3
# sync 4
# Regular users
awk -F: '$3 >= 1000 && $3 < 65534 { print $1, $3 }' /etc/passwd
# alice 1000
# bob 1001
# carol 1002
# ============================================
# PART 4: READ /etc/group
# ============================================
head -5 /etc/group
# root:x:0:
# daemon:x:1:
# bin:x:2:
# sys:x:3:
# adm:x:4:syslog,alice
grep developers /etc/group
# developers:x:1001:alice,bob,carol
# ============================================
# PART 5: GROUP MEMBERSHIP
# ============================================
# Supplementary members from /etc/group
grep sudo /etc/group
# sudo:x:27:alice
# Primary group from /etc/passwd
grep alice /etc/passwd | awk -F: '{ print "GID:", $4 }'
# GID: 1000
# Complete view with id
id alice
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1001(developers)
# ============================================
# PART 6: FIND ACCOUNTS WITH REAL SHELLS
# ============================================
grep -v -E '/nologin|/false' /etc/passwd
# root:x:0:0:root:/root:/bin/bash
# sync:x:4:65534:sync:/bin:/bin/sync
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
# bob:x:1001:1001:Bob Jones:/home/bob:/bin/bash
# carol:x:1002:1002:Carol White:/home/carol:/bin/bash
# ============================================
# PART 7: GETENT VS CAT
# ============================================
getent passwd alice
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
getent passwd 1000
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
getent group developers
# developers:x:1001:alice,bob,carol
# Count entries
getent passwd | wc -l
# 42
# ============================================
# PART 8: SHADOW FILE (ROOT ONLY)
# ============================================
sudo head -1 /etc/shadow
# root:$6$rounds=5000$xyz...:19000:0:99999:7:::
# Check password aging
sudo chage -l alice
# Last password change : Mar 15, 2026
# Password expires : never
# Password inactive : never
# Account expires : never
# Minimum number of days between password change : 0
# Maximum number of days between password change : 99999
# Number of days of warning before password expires : 7
# ============================================
# PART 9: CURRENT SESSION
# ============================================
who
# alice pts/0 2026-03-15 10:22 (192.168.1.10)
w
# 10:50:12 up 3 days, 1 user, load average: 0.15, 0.10, 0.05
# USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
# alice pts/0 192.168.1.10 10:22 0.00s 0.15s 0.02s w
id
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1001(developers)
# ============================================
# PART 10: LOGIN HISTORY
# ============================================
last | head -5
# alice pts/0 192.168.1.10 Sat Mar 15 10:22 still logged in
# bob pts/1 192.168.1.11 Sat Mar 15 10:45 still logged in
# alice pts/0 192.168.1.10 Fri Mar 14 09:15 - 17:30 (08:15)
lastlog | head -5
# Username Port From Latest
# root **Never logged in**
# daemon **Never logged in**
# bin **Never logged in**
# sys **Never logged in**
# alice pts/0 192.168.1.10 Sat Mar 15 10:22:14 +0000 2026
# ============================================
# PART 11: AUDIT โ USERS WITH UID 0
# ============================================
awk -F: '$3 == 0 { print $1 }' /etc/passwd
# root
# (only root should appear)
# ============================================
# PART 12: AUDIT โ PASSWORDLESS ACCOUNTS
# ============================================
sudo awk -F: '$2 == "" { print $1 }' /etc/shadow
# (empty output is good โ no passwordless accounts)
Each part covers one inspection task. Parts 1 through 6 read the files directly. Part 7 shows getent. Part 8 reads shadow data safely. Parts 9 and 10 show session and history. Parts 11 and 12 are security audits.
Quick Reference
The Identity Files
| File | Purpose | Permissions |
|---|---|---|
/etc/passwd | User accounts | 644 (world-readable) |
/etc/group | Group definitions | 644 (world-readable) |
/etc/shadow | Password hashes | 640 (root only) |
/etc/gshadow | Group passwords | 640 (root only) |
Field Extraction
| Task | Command |
|---|---|
| Usernames only | cut -d: -f1 /etc/passwd |
| UID + name | awk -F: '{ print $3, $1 }' /etc/passwd |
| System accounts | awk -F: '$3 < 1000' /etc/passwd |
| Regular users | awk -F: '$3 >= 1000 && $3 < 65534' /etc/passwd |
| Real shells | grep -v -E '/nologin|/false' /etc/passwd |
| Group members | grep groupname /etc/group |
getent Databases
| Database | Queries |
|---|---|
passwd | Users |
group | Groups |
shadow | Password hashes |
hosts | Hostnames |
services | Network services |
Session Commands
| Command | Output |
|---|---|
who | Logged-in sessions |
w | Sessions + activity |
id | Current identity |
whoami | Current username |
last | Login history |
lastb | Failed login history |
lastlog | Last login per user |
Security Audits
| Query | Command |
|---|---|
| UID 0 accounts | awk -F: '$3 == 0' /etc/passwd |
| Passwordless | sudo awk -F: '$2 == ""' /etc/shadow |
| Real shells | grep -v -E '/nologin|/false' /etc/passwd |
| Never logged in | lastlog | grep 'Never' |
| Failed logins | sudo lastb |
Best Practices
โ Do This:
# Use getent for reliable lookups
getent passwd alice # โ
# Use awk -F: for field extraction
awk -F: '{ print $1, $3 }' /etc/passwd # โ
# Check UID ranges to distinguish account types
awk -F: '$3 < 1000' /etc/passwd # โ
# Use chage -l for password policy
sudo chage -l alice # โ
# Verify session identity before debugging
id # โ
# Review login history
last | head -20 # โ
โ Don’t Do This:
# Don't read /etc/shadow without root
cat /etc/shadow # Permission denied # โ ๏ธ
# Don't assume /etc/passwd has all users
# Directory services may add more # โ ๏ธ
# Don't edit identity files by hand
vim /etc/passwd # use useradd/usermod # โ ๏ธ
# Don't parse shadow directly when chage exists
# chage handles the edge cases # โ ๏ธ
# Don't forget primary group is in /etc/passwd
# Member lists in /etc/group are supplementary only # โ ๏ธ
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
grep misses remote users | File has only local accounts | Use getent |
| Group member list incomplete | Primary group in /etc/passwd | Check both files |
/etc/shadow unreadable | Expected โ root only | Use sudo |
| UID shown without name | Stale UID | Check /etc/passwd |
last history short | Log rotation | Check rotation policy |
awk field wrong | Miscounted colons | Verify field number |
getent passwd slow | Directory service | Use targeted lookup |
| Editing passwd breaks login | Malformed line | Use vipw or tools |
Real-World Examples
1. List all usernames
cut -d: -f1 /etc/passwd
2. Find a user’s UID
getent passwd alice | cut -d: -f3
3. List system accounts
awk -F: '$3 < 1000 { print $1 }' /etc/passwd
4. List human users
awk -F: '$3 >= 1000 && $3 < 65534 { print $1 }' /etc/passwd
5. Find accounts with real shells
grep -v -E '/nologin|/false' /etc/passwd
6. List group members
getent group developers
7. Check password policy
sudo chage -l alice
8. Audit UID 0 accounts
awk -F: '$3 == 0 { print $1 }' /etc/passwd
9. Find never-logged-in accounts
lastlog | grep 'Never'
10. Review recent logins
last | head -20
Visual: /etc/passwd Structure
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash โ
โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ โโโ shell โ
โ โ โ โ โ โ โโโ home dir โ
โ โ โ โ โ โโโ comment (GECOS) โ
โ โ โ โ โโโ primary GID โ
โ โ โ โโโ UID โ
โ โ โโโ password placeholder โ
โ โโโ username โ
โ โ
โ Colon-separated, position-sensitive, no header. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Primary vs Supplementary Membership
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ /etc/passwd: โ
โ alice:x:1000:1000:... โ
โ โ โ
โ โโโ primary GID = 1000 (alice) โ
โ โ
โ /etc/group: โ
โ alice:x:1000: โ
โ (empty member list โ alice is here by primary GID) โ
โ โ
โ sudo:x:27:alice โ
โ (supplementary membership) โ
โ โ
โ developers:x:1001:alice,bob,carol โ
โ (supplementary membership) โ
โ โ
โ id alice: โ
โ groups=1000(alice),27(sudo),1001(developers) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: getent vs cat
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STANDALONE SYSTEM โ
โ โ
โ cat /etc/passwd โโโบ local accounts โ
โ getent passwd โโโบ local accounts โ
โ โ
โ Same result. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ DIRECTORY-CONNECTED SYSTEM (LDAP, SSSD) โ
โ โ
โ cat /etc/passwd โโโบ local accounts only โ
โ getent passwd โโโบ local + directory accounts โ
โ โ
โ Different results. getent shows the full picture. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Inspection Decision Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ What do you need to know? โ
โ โ โ
โ โโโ A specific user's identity? โ
โ โ โโโ id username / getent passwd username โ
โ โ โ
โ โโโ All local accounts? โ
โ โ โโโ cat /etc/passwd โ
โ โ โ
โ โโโ All accounts (incl. remote)? โ
โ โ โโโ getent passwd โ
โ โ โ
โ โโโ Who is logged in now? โ
โ โ โโโ who / w โ
โ โ โ
โ โโโ Who logged in recently? โ
โ โ โโโ last / lastlog โ
โ โ โ
โ โโโ Password policy? โ
โ โโโ sudo chage -l username โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Security Audit Checklist
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. UID 0 accounts (only root) โ
โ awk -F: '$3 == 0' /etc/passwd โ
โ โ
โ 2. Passwordless accounts โ
โ sudo awk -F: '$2 == ""' /etc/shadow โ
โ โ
โ 3. Accounts with real shells โ
โ grep -v -E '/nologin|/false' /etc/passwd โ
โ โ
โ 4. Never-logged-in accounts โ
โ lastlog | grep 'Never' โ
โ โ
โ 5. Recent failed logins โ
โ sudo lastb โ
โ โ
โ 6. Recent successful logins from unexpected IPs โ
โ last | head -50 โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| File | Read With | Contains |
|---|---|---|
/etc/passwd | cat, grep, awk | User accounts |
/etc/group | cat, grep, awk | Group definitions |
/etc/shadow | sudo cat, chage -l | Password hashes |
/etc/gshadow | sudo cat | Group passwords |
| Query | Tool |
|---|---|
| User by name/UID | getent passwd |
| Group by name/GID | getent group |
| Current identity | id, whoami |
| Current sessions | who, w |
| Login history | last, lastlog |
| Failed logins | lastb |
| Password policy | chage -l |
Key takeaways:
/etc/passwdand/etc/groupare plain text with fixed field order โ seven fields for users, four for groups, colon-separated/etc/shadowholds the password hashes and is readable only by root;chage -lis the safe way to read aging datagetentis preferred overcatbecause it queries the system’s full identity source, not just the local files- A user’s primary group is in
/etc/passwd, not/etc/groupโ the member list in/etc/groupholds only supplementary members awk -F:is the standard tool for extracting fields and filtering by UID rangeidis the fastest way to see a user’s complete identity โ UID, primary GID, and all supplementary groupswho,w,last, andlastlogshow current and historical sessions โ the starting point for any access review- Security audits follow predictable queries โ UID 0 accounts, passwordless accounts, real shells, never-logged-in accounts, failed logins
- System accounts live in the same files as human accounts โ the UID range (below 1000) is how to tell them apart
Remember: The identity files are the reference for who exists on a Linux system, and getent is the tool that shows what the system actually resolves. Reading them is a matter of knowing the field order and using awk -F: to extract what you need. The session and history commands โ id, who, last, lastlog โ answer the questions about who is here now and who was here before. Together they cover the full range of user and group inspection, from a single lookup to a system-wide audit.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!