Linux online course

/etc/shadow File Format and Password Aging in Linux

Learn how Linux /etc/shadow stores password hashes, account-aging fields, expiration dates, locks, and safe administration commands.

/etc/shadow is the protected local-account database used by Linux systems. It stores password-verification data and password-aging metadata for local users. Understanding its fields helps administrators diagnose password expiration, account locks, and temporary-account policies.

Purpose of /etc/shadow

A password hash is a one-way derived value used to verify a submitted password. During authentication, the system processes the password supplied by the user and compares the resulting hash with the stored value. It does not normally decrypt a stored password, because the original password is not stored in reversible form.

Password-hash records are separated from the general account information in /etc/passwd. Many programs need to read usernames, user IDs, home directories, or login shells, but they should not receive password-verification data. The separation allows broader read access to basic account information while protecting sensitive hash data.

Access control and security

Ordinary users normally cannot read /etc/shadow. Access is generally limited to root and privileged account-management utilities, although the exact owner, group, and permission arrangement varies by distribution.

Do not copy the file unnecessarily, expose it in logs or bug reports, or make it world-readable. Do not broadly change its permissions to solve an access problem. Use authorized tools such as chage and passwd instead of editing the file directly.

Record structure

The file contains one account record per line. Each record has colon-delimited fields:

username:password:lastchg:min:max:warn:inactive:expire:reserved

The conventional layout has nine fields. A field can be empty, and the meaning of an empty field depends on that field's position. The following example uses an abbreviated, fictional hash:

alice:$y$j9T$example...:16182:0:30:7:::
PositionField nameExample valueMeaningEmpty or special-value behavior
1usernamealiceLocal login name, corresponding to the username in /etc/passwd.Should identify the account record.
2password$y$j9T$example...Password hash, often represented using modular crypt format.Markers such as ! or * commonly make password authentication unusable. An empty value has security implications and depends on PAM and distribution policy.
3lastchg16182Days since 1970-01-01 UTC when the password was last changed.0 generally forces a password change at the next successful login.
4min0Minimum number of days before the password may be changed again.0 permits an immediate change.
5max30Maximum number of days the password remains valid.A large value such as 99999 is effectively no expiration in many configurations, but policy and tool behavior should be checked.
6warn7Number of days before password expiration during which warnings are shown.Behavior for an empty value can vary by policy and implementation.
7inactiveemptyNumber of days after password expiration before password-based use is disabled because the password was not changed.An empty field is not the same as a numeric inactivity period; it normally means no post-expiration inactivity interval is configured.
8expireemptyAbsolute account-expiration date, expressed as days since the Unix epoch.Empty normally means no account-expiration date is configured.
9reservedemptyReserved for future use.Normally empty; do not repurpose it.

Understanding the password field

The password field normally contains a password hash. It may use the modular crypt format, a representation that can encode an algorithm identifier, options, a salt, and the resulting hash. A salt is stored with the hash data so that identical passwords do not produce identical stored values.

Password-field patternTypical interpretationAdministrative implication
Normal modular hashPassword authentication can be checked against the stored hash.Still protect the file; hashes are sensitive even though they are not plaintext passwords.
Leading exclamation mark, such as !$y$...Password authentication is commonly locked.Use passwd -l or another supported tool to manage the lock. Other authentication methods may be governed separately.
Asterisk or another unusable valuePassword login is commonly prevented; this is frequent for service or system accounts.Do not assume the account is disabled in every possible authentication path.
Empty fieldNo stored password hash is present.This is not a normal secure configuration. Whether login is accepted depends on PAM and distribution policy; investigate and correct it through supported administration tools.

Converting lastchg and expire values

The Unix epoch is the reference date 1970-01-01. In shadow records, lastchg and expire use a count of days from that date, rather than a human-readable calendar date.

For example, a record with lastchg=16182 has a password-change date of 2014-04-22. On GNU/Linux, convert it with:

date -u -d '1970-01-01 + 16182 days' +%F

Using UTC avoids confusion caused by local time zones. For administrative verification, prefer the readable output from chage -l.

Password and account aging

Password expiration and account expiration are separate controls. max limits the password's lifetime; warn controls advance warnings; inactive controls what happens after an expired password remains unchanged; and expire sets an absolute end date for the account itself.

EventRelevant fieldWhen it occursEffect on the user
Password changedlastchgWhen the password is set or changed.The password-aging clock starts again.
Warning interval beginswarn and maxwarn days before the password reaches its maximum age.The user receives password-expiration warnings.
Password expiresmaxAfter the maximum password age has elapsed.The user is generally required to change the password before normal password use continues.
Inactive interval endsinactiveThe configured number of days after password expiration.Password-based account use may be disabled because the expired password was not changed.
Account reaches absolute expiration dateexpireOn the configured epoch-day date.The account can be prevented from use independently of the password's age.

For the sample values lastchg=16182, max=30, and warn=7, the password was changed on 2014-04-22. It becomes due for change 30 days later, and warnings begin seven days before that due date. Because inactive and expire are empty, the record does not show a configured post-expiration inactivity interval or fixed account-expiration date.

A different record may have password aging but no account expiration:

alice:$y$j9T$example...:16182:0:30:7:::

Here, max and warn are populated while expire is empty. A password can therefore expire even though no fixed date has been configured to end the account.

For a temporary contractor account, an expire value can be populated:

contractor:$y$j9T$example...:19800:0:60:14:7:20000:

This account has a password lifetime, a seven-day post-expiration inactivity period, and an absolute account-expiration date. The absolute date is separate from the password's expiration schedule and can prevent account use even if the password is otherwise current.

Safe inspection and administration

Use account-management commands rather than manually editing /etc/shadow. When account sources may be configured through the Name Service Switch, getent is preferable because it follows the configured account lookup mechanism:

sudo getent shadow USERNAME

To inspect one exact local record directly:

sudo grep '^USERNAME:' /etc/shadow

The direct command is useful for local-file inspection, but it does not account for non-file account sources. Display password-aging information in readable form with:

sudo chage -l USERNAME

Some passwd implementations also provide concise status information:

sudo passwd -S USERNAME

Set a minimum age of zero days, a maximum age of 30 days, and a seven-day warning period with:

sudo chage -m 0 -M 30 -W 7 USERNAME

Set an absolute account-expiration date with a supported tool:

sudo chage -E YYYY-MM-DD USERNAME

Lock password authentication using the password-management utility:

sudo passwd -l USERNAME

Changes to local account records should be coordinated with /etc/passwd and performed through supported tools. Direct edits risk malformed records, inconsistent account data, or unexpected behavior from PAM and other authentication components.

Troubleshooting

The user is unexpectedly required to change a password

  • Run sudo chage -l USERNAME and inspect the last-change date and maximum age.
  • Check whether lastchg is zero, which generally forces a change at the next successful login.
  • Check whether the password has passed its maximum age.
  • Verify the system date and time if the calculation appears incorrect.

The user cannot log in after the password expired

  • Determine whether the password is merely expired or whether the configured inactive period has elapsed.
  • Check the inactive period and account-expiration date with sudo chage -l USERNAME.
  • Use authorized recovery procedures rather than modifying /etc/shadow by hand.

A password reset does not permit authentication

  • Check whether the password field is locked with a leading !.
  • Check whether an absolute account-expiration date has passed.
  • Review PAM policy, the login shell, account status, and other restrictions that can prevent login independently of the password hash.

The computed expiration date differs by one day

  • Use UTC for epoch-day conversion.
  • Remember that policy comparisons may use calendar-date boundaries rather than an elapsed 24-hour interval.
  • Use chage -l as the primary human-readable verification tool.

An unprivileged user receives permission denied

This is normally expected. Use sudo only when authorized, and do not weaken /etc/shadow permissions.

Exam-relevant notes

  • /etc/shadow stores password hashes and aging metadata, not ordinary plaintext passwords.
  • Fields are colon-delimited, with one account record per line.
  • lastchg, expire, and related date values use days since the Unix epoch.
  • min is the waiting period before another password change; max is the password lifetime; warn is the advance-warning period.
  • inactive is a post-password-expiration inactivity setting, not simply the current disabled state.
  • expire is an absolute account-expiration date and is independent of password expiration.
  • A leading ! commonly locks password authentication, while * or another invalid hash commonly prevents password login.
  • Use passwd, chage, and other supported tools instead of directly editing the shadow file.

For related Linux command and filesystem fundamentals, see Linux and Bourne Again Shell (Bash).