How can I list all locked users in Linux?

usermod -L user_name

This command locks a particular user. Does Linux have any command that lists locked user?


passwd -S -a | grep LK | cut -d " " -f1 and/or passwd -S -a |awk '/LK/{print $1}' should work.

(in case your interested)

Both of these illustrations demonstrate a very common technique that is used throughout Unix/Linux: what I'll call command piping.

In these examples, the output of one command (such as ls is "piped to" another command, which effectively filters its input and sends it down the line.

Refer to LinuxQuestions.org for more information.

| improve this answer | |
  • And of course this works only if user data is local, and not in some kind of a database (LDAP, etc.). But I suppose this is what the OP wanted. – haimg Dec 18 '11 at 16:32
  • @haimg Yes. If you want to edit my question to include that information, feel free. – wizlog Dec 18 '11 at 16:36
sudo awk '/!\*/' /etc/shadow | cut -d : -f1

Another way for local users.

| improve this answer | |

The existing answers are imprecise: they will get false negatives on accounts that are locked using a different technique than how usermod -L does it, and they will get false positives on accounts that can be logged into using an SSH key but not with a password.

To do a comprehensive job on a system with local passwd and shadow files and an active SSH daemon you have to check for all of these cases:

  • First look at the shell field of /etc/passwd; if it is one of /bin/false, /sbin/nologin, or /usr/sbin/nologin, the account is unconditionally locked. (In principle you could use anything that's not a valid shell program, but there's no easy way to define "valid shell program", and special-purpose accounts with unusual programs in that field are pretty common, you don't want to assume those are locked.)

  • For accounts that have a valid shell, next check whether ~user/.ssh/authorized_keys or ~user/.ssh/authorized_keys2 exists, is nonempty, and has appropriate access privileges. (The file, and all of its parent directories, must be owned by either the user or root, and must be unwritable by all other accounts.) If so, the account can be logged into using some SSH key, even if there is no password. Depending on the PAM and sshd configuration, it may be possible to disable such accounts using the "account expiration date" field in /etc/shadow, but it's safest to assume this is not possible.

  • For accounts that have a valid shell and no authorized_keys, next check /etc/shadow. There are three possibilities for the password field: If it is empty, the account can be used without specifying any password. (PAM can be configured to block access to this type of account, but I would never assume this has been done.) If it is the valid crypt(3) hash of some password, then the account can be accessed using that password. Any other string means the account cannot be accessed using a password. Conventionally you will see one of *, !, or *LK* used.

    Unfortunately, there is no simple way to decide whether or not a string is the valid crypt(3) hash of some password. My recommendation here is to treat any string that starts with either * or ! as indicating that the account cannot be logged into using a password, and any other string as indicating that it can.

  • Technically the "maximum password age", "password inactivity period", and "account expiration date" fields of /etc/shadow can also be used to disable a user account, but I would hesitate to rely on these as the sole means of locking an account, and so I wouldn't look at them when deciding whether an account is locked, either.

  • Technically the password field of an /etc/passwd record could contain something other than the magic token x (meaning "go look in /etc/shadow") but nowadays that indicates a catastrophically misconfigured operating system. If I ever saw that I would assume the box had been pwned and go into disaster recovery mode.

This Python script (it must be run as root, since it reads /etc/shadow and pokes into everyone's home directory) will print the login names of all unlocked users. This is usually more useful than the list of all locked users, since that includes a bunch of uninteresting system accounts.

#! /usr/bin/python3

import os
import stat
import sys

def get_homes_and_uids_for_users_with_shells():
    users = {}
    with open("/etc/passwd", "rt") as pf:
        for line in pf:
            login, x, uid, gid, gecos, home, shell = line.split(':')
            if x != 'x':
                sys.stderr.write("*** Account '{!r}' not properly shadowed\n"
            if shell not in ('/bin/false', '/usr/bin/false',
                             '/sbin/nologin', '/usr/sbin/nologin'):
                users[login] = (int(uid), home)
    return users

def check_ssh_auth_perms(path, owner):
    owners = (0, owner)
    badwritebits = stat.S_IWGRP | stat.S_IWOTH # 0022
    # FIXME: I'm not sure whether sshd allows symlinks at any point in this
    # path.  Conservatively assume it does.
    # FIXME: Doesn't check for ACLs.
        st = os.stat(path)
    except FileNotFoundError:
        return False
    if (st.st_size == 0 or st.st_uid not in owners
        or not stat.S_ISREG(st.st_mode)
        or stat.S_IMODE(st.st_mode) & badwritebits):
        return False
    while True:
        path = os.path.dirname(path)
        # Not necessary to check for ENOENT; if we got here at all,
        # the entire chain of parent dirs must exist
        st = os.stat(path)
        if (st.st_uid not in owners
            or not stat.S_ISDIR(st.st_mode)
            or stat.S_IMODE(st.st_mode) & badwritebits):
            return False
        if path == '/': break
    return True

def get_users_with_ssh_keys(all_users):
    ssh_users = set()
    already_processed_homes = {}
    for login, (uid, home) in all_users.items():
        if home in already_processed_homes:
            if already_processed_homes[home]:
        if (check_ssh_auth_perms(home + "/.ssh/authorized_keys", uid)
            or check_ssh_auth_perms(home + "/.ssh/authorized_keys2", uid)):
            already_processed_homes[home] = True
            already_processed_homes[home] = False
    return ssh_users

def get_users_with_possible_passwords():
    pw_users = set()
    with open("/etc/shadow", "rt") as sf:
        for line in sf:
            login, phash, chg, mina, maxa, warn, inact, expir, res \
                = line.split(':')
            if not phash:
                sys.stderr.write("*** Account '{!r}' has blank password\n"
            if phash[0] != '*' and phash[0] != '!':
    return pw_users

def main():
    users = get_homes_and_uids_for_users_with_shells()
    ssh_users = get_users_with_ssh_keys(users)
    pw_users = get_users_with_possible_passwords()

    active_users = set(users.keys()) & (ssh_users | pw_users)
    for u in sorted(active_users):
        sys.stdout.write(u + "\n")


It's even more complicated if you have to worry about accounts supplied by a network authentication service (e.g. NIS, LDAP, Kerberos). I don't know how to expand this answer to cover those.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.