Home / Alt manpages / shadow(5)

  • shadow(5)
  • File format
  • linux

Inspect and Safely Reason About /etc/shadow

You will identify what the nine fields in /etc/shadow mean, inspect an account without exposing its password hash to ordinary users, and spot the difference between a locked password, an expired password and an expired account. Allow about fifteen minutes. You need a shell and the passwd package, which provides shadow-utils 4.13 on the system used for these examples.

Security boundary

/etc/shadow contains password information. Do not paste its contents into tickets, chat, terminal recordings or shell history. The examples that read it directly require elevated privileges. Changing it by hand can lock users out or weaken authentication; use the account-management tools for changes.

1. Confirm the file and its protection

First check that the expected file exists and that only root can read it. This is a read-only command and does not need elevated privileges:

$ command -v getent
/usr/bin/getent
$ ls -l /etc/shadow /etc/shadow-
-rw-r----- 1 root shadow ... /etc/shadow
-rw-r----- 1 root shadow ... /etc/shadow-

The exact group and permission bits can vary with distribution policy. The useful result is that the file is owned by root and is not world-readable. If your output grants read access to every user, stop and fix the host's account-file permissions through your normal privileged administration process before treating the system as secure.

/etc/shadow- is a backup used by tools from the shadow toolsuite. The manual warns that not every password-management program uses it, so do not assume it is a complete or current backup.

2. Read one record without displaying the hash

Use sudo only for the narrow read. Replace ACCOUNT_NAME with an account you are authorised to inspect:

$ sudo awk -F: -v account='ACCOUNT_NAME' '$1 == account { print "account=" $1, "last_change=" $3, "min_age=" $4, "max_age=" $5, "warning=" $6, "inactive=" $7, "expiry=" $8, "reserved=" $9 }' /etc/shadow
account=ACCOUNT_NAME last_change=... min_age=... max_age=... warning=... inactive=... expiry=... reserved=...

This deliberately omits field 2, the encrypted-password field. A missing line means the name is not present in /etc/shadow; it does not prove that the account is absent from every identity source. For a local account, compare the name with getent passwd ACCOUNT_NAME without printing any shadow data.

Checkpoint: if you need to confirm the record exists while keeping output safe, print only the account name:

$ sudo awk -F: -v account='ACCOUNT_NAME' '$1 == account { print $1; found=1 } END { exit !found }' /etc/shadow
ACCOUNT_NAME

3. Interpret the password field safely

The second field controls Unix password authentication, but it is not a value to edit casually. An empty field means no password is required for that login name, although an application may refuse access when it sees an empty field. A field beginning with ! means the password is locked; the characters after it preserve the former password field. Values such as ! or * are not valid crypt(3) results, so a Unix password cannot authenticate, while another login method might still work.

To classify a local account without printing its hash, inspect only the first two characters:

$ sudo awk -F: -v account='ACCOUNT_NAME' '$1 == account { if ($2 == "") print "password field: empty"; else if ($2 ~ /^!/) print "password field: locked"; else if ($2 ~ /^\*/) print "password field: non-crypt marker"; else print "password field: hash present" }' /etc/shadow
password field: locked

Do not infer that a locked password makes the whole account unusable. The manual distinguishes password authentication from other ways of logging in. Check the service and authentication policy as well.

4. Work through password ageing

Fields 3 through 7 are day counts relative to 1 January 1970 UTC:

  • Field 3 is the last password change. A value of 0 requests a password change at the next login. An empty field disables password ageing.
  • Field 4 is the minimum age. Empty or 0 means the password can be changed without waiting.
  • Field 5 is the maximum age. Once it elapses, the password may still work until the next login asks for a change. If it is lower than field 4, the user cannot change the password.
  • Field 6 is the warning period before expiry. Empty or 0 means no warning period.
  • Field 7 is the inactivity period after password expiry. Once it elapses, password login is no longer possible and an administrator must help.

An empty maximum-age field also means there is no maximum age, warning period or inactivity enforcement. That default is easy to miss when scanning colon-separated output.

5. Separate account expiry from password expiry

Field 8 is the account expiry date, also measured in days since 1 January 1970 UTC. An expired account cannot log in at all. Password expiry is narrower: it blocks password login, while another authentication method may have different behaviour. An empty account-expiry field means the account does not expire. Do not write 0 to this field: the manual says it is ambiguous between no expiry and 1 January 1970.

Convert a non-empty day count for a human check without changing the file:

$ days=ACCOUNT_EXPIRY_DAYS
$ date -u -d "1970-01-01 +${days} days" '+%Y-%m-%d UTC'
2030-01-15 UTC

Replace the placeholder with digits from your authorised inspection. An empty value needs no conversion and means no account expiry. If the date is unexpected, stop and use the distribution's account-management command to correct it. Do not patch the colon-separated line while logged in over a fragile remote connection.

6. Recover from a suspicious or failed edit

There is no safe universal undo for a hand-edited shadow file. Before any planned maintenance, confirm that your organisation has a tested recovery path and that another administrative session is available. If a change has already caused failed logins, preserve the current file for investigation, check /etc/shadow- as a possible tool-created backup, and use the installed password and account-management tools to restore a known-good state. Do not copy a backup over /etc/shadow blindly: it may be stale, have the wrong owner or permissions, or omit newer accounts.

After any authorised tool-based change, repeat the permission check and the hash-free field inspection. A successful command exit only shows that the tool accepted the request; it does not prove that the resulting policy matches your intended login behaviour.

Done means

  • /etc/shadow is root-owned and not readable by ordinary users.
  • You inspected the target account without printing its password hash.
  • You can distinguish a locked password from password ageing and account expiry.
  • Empty fields and the special value 0 were interpreted according to their field, not guessed from the surrounding values.
  • No hand edit was made without a tested recovery path and a second administrative session.