Identity Security and PAM Blog for CISOs and IT Security Pros

How to List Every User and Group on a Linux Server

Written by Steve Salinas | Jun 5, 2025, 12:00:00 PM

The first question asked in every audit and the first question asked after every incident is always the same.

"Who can log in to this server?"

Most admins answer it with cat /etc/passwd, which is a third of the answer. It misses accounts that come from a directory, says nothing about who is logged in now and hides the detail that matters most: which of those accounts can become root.

Every account on the list is a credential. The accounts you don't know about are the ones nobody rotates, reviews or removes. This blog covers how to list local and directory users, filter the list to humans, see who is logged in now and recently, list groups and their members, find who holds sudo and wheel, and identify the point at which a per-server inventory stops scaling.

List every user account

Read /etc/passwd

Every local account is one line in /etc/passwd, with seven colon-separated fields: username, password placeholder (the hash lives in /etc/shadow), user ID (UID), primary group ID (GID), description, home directory and login shell.

cut -d: -f1 /etc/passwd

That prints the usernames alone. Keep the full lines when you audit, because the UID and shell fields tell you what each account is for.

Use getent to include directory accounts

getent asks the Name Service Switch, so it returns accounts from every source listed in /etc/nsswitch.conf: local files plus LDAP or Active Directory through SSSD.

getent passwd

One caveat decides whether this list is complete. SSSD does not enumerate directory users by default, so a bare getent passwd on a domain-joined server still shows only local accounts.1 A direct lookup works regardless:

getent passwd alice

If the account comes back and isn't in /etc/passwd, it's a directory account. The inventory of those lives in the directory, not on the server. In an interactive bash session, compgen -u prints the same names getent passwd would, with less typing.

Filter the list down to people

System and service accounts outnumber people on most servers. Regular users start at UID 1000 on Debian, Ubuntu and RHEL-family systems (the UID_MIN value in /etc/login.defs). On Debian and Ubuntu, nobody sits at 65534, the kernel’s overflow UID. RHEL-family systems traditionally reserve 99 for nobody instead, so the filter below excludes 65534 defensively rather than because every distribution uses it.

awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd

Use >=, not >. The first regular user on an Ubuntu system is UID 1000, and a filter that starts at 1001 skips the account that was created at install time.

See last logins with lslogins

lslogins, part of util-linux, combines /etc/passwd, /etc/shadow and the login records into one table with UID, process count, password lock status and last login.

lslogins -u

-u limits the output to regular user accounts. The LAST-LOGIN column is the fastest way to spot an account nobody has used in months.

Find who is logged in right now

who
w

who lists each session with its terminal, login time and source address. w adds what each session is running. For history, last -n 20 shows the most recent logins and last alice shows one user's.

List every group and who is in it

A user's reach comes from group membership, so the user list is only half the inventory.

Read /etc/group

Each line in /etc/group has four fields: group name, a password placeholder, the GID and a comma-separated list of supplementary members. The password field is a holdover; /etc/gshadow holds anything sensitive.

getent group

As with users, getent includes directory groups where enumeration allows and cat /etc/group shows only local ones. System groups sit below GID 1000 and user-created groups above it:

getent group | awk -F: '$3 >= 1000' | sort -t: -k3 -n

List one user's groups

id alice
groups alice

Both print the primary group and every supplementary group. There is no list groups command in Linux; groups with no argument prints your own memberships, and id adds the numeric IDs:

uid=1001(alice) gid=1001(alice) groups=1001(alice),27(sudo),1002(developers)

Read that line as a risk statement, not a lookup: alice is in sudo, so alice can become root.

List one group's members

getent group developers The fourth field holds the supplementary members. It does not hold anyone whose primary group is developers, so a user created with useradd -g developers won't appear there. To catch both:

getent group developers | cut -d: -f4
awk -F: -v gid="$(getent group developers | cut -d: -f3)" '$4 == gid {print $1}'
/etc/passwd

The first line prints supplementary members; the second prints users whose primary group matches.

Find who can become root

This is the part of the inventory an auditor reads first. Five checks cover it:

getent group sudo wheel docker
sudo -l -U alice
awk -F: '$3 == 0 {print $1}' /etc/passwd
sudo awk -F: '$2 == "" {print $1}' /etc/shadow
awk -F: '$7 !~ /(nologin|false)$/ {print $1}' /etc/passwd

In order, the five check are:

  1. the members of the administrator groups (sudo on Debian and Ubuntu, wheel on RHEL and Fedora, and docker on any host, because docker group members can run containers as root).

  2. what one user is allowed to run through sudo, including rules granted in /etc/sudoers.d/ that group membership alone won't reveal2.

  3. any account other than root with UID 0; any account with an empty password field.

  4. every account that still has a login shell.

  5. service accounts belong in the last list only if someone can explain why.

Run the five on a new server and the output fits on one screen. Run them on a server that has been in production for three years and you'll meet accounts nobody remembers creating.

Table: The commands in one place

Question Command
Which local accounts exist? cut -d: -f1 /etc/passwd
Which accounts exist, including directory accounts? getent passwd (direct lookups work even when enumeration is off)
Which accounts belong to people? awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd
When did each account last log in? lslogins -u
Who is logged in now? who, w
Which groups is alice in? id alice
Who is in developers? getent group developers
Who can become root? getent group sudo wheel docker, then sudo -l -U per user
Which accounts have UID 0? awk -F: '$3 == 0 {print $1}' /etc/passwd

Turn the list into an inventory

A list is a snapshot. An inventory is the same list, kept over time, with an owner for every row. Three habits get you there:

  1. Save the output of the commands above per server and diff it monthly. New accounts, new sudo members and new UID 0 entries are findings until someone explains them.

  2. Give every account an owner and a reason. An account with neither is an orphan, and orphans are what a leaver's access looks like six months later.

  3. Review group membership, not file permissions. If access is granted through groups, a user access review is a list of group members rather than a crawl through the filesystem.

Where a per-server inventory stops scaling

Auditing five servers takes a morning. Auditing fifty requires scripts and spreadsheets and introduces drift: manually created local accounts, inconsistent sudoers files, and directory accounts omitted by a basic getent passwd query. At that scale, “who can become root where?” has fifty separate answers, with no single, complete view.

Privilege Control for Servers answers it in one place. It discovers the servers, accounts and privileges in your environment and keeps that inventory current as servers and identities change. It joins Linux and Unix servers to Active Directory, so people log in with one identity instead of a local account per server, and it replaces standing sudo and wheel membership with just-in-time elevation that ends when the task does.

Secret Server Discovery finds the local and service accounts that remain, vaults their credentials and rotates them.

For your admins, that means the five checks above run themselves across the fleet. For whoever owns your next audit, it means one report of every privileged account on every Linux server, with an owner and a last-used date on each row.

Schedule a demo and see the privileged accounts across your Linux servers in one inventory.