VMware ESXi and vSphere Cluster Management
Understanding the Linux /etc/shadow File Format
Learn how Linux stores password hashes and password-aging policies in /etc/shadow, including all nine colon-separated fields and safe administration commands.
What /etc/shadow Does
/etc/shadow is a protected local Linux account database. It stores password-hash data and password-aging metadata, such as when a password was last changed and when it should expire.
/etc/passwd normally contains account identity information: the login name, user ID, group ID, home directory, and login shell. Its password column commonly contains an x placeholder rather than the password data. Sensitive password and aging information is normally kept in /etc/shadow.
A password is not stored as a reversibly encrypted value. Instead, Linux stores a password hash: a one-way derived representation used to compare a submitted password with the stored result. A salt is additional per-password input included during hashing, making precomputed hash tables less useful.
When the account is local, authentication components such as PAM (Pluggable Authentication Modules) commonly consult shadow data. The actual result also depends on PAM policy, NSS configuration, account state, and any centralized identity service.
Access Control and Security
Ordinary users should not be able to read /etc/shadow. Typical systems make it owned by root and assign restrictive permissions, although the exact owner, group, and mode vary by distribution. Inspect the current metadata instead of assuming a universal mode:
sudo stat -c '%A %U:%G %n' /etc/shadowHashes are not plaintext passwords, but they are still sensitive. An attacker who obtains them can attempt offline password guesses, especially when users choose weak or reused passwords. Do not copy, publish, or broadly share shadow entries.
Use account-management tools such as passwd, chage, and usermod for normal changes. Direct editing is error-prone and can cause authentication failures.
Record Structure
The file contains one account record per line. Each record has nine standard fields separated by colons:
login:password:last_change:min_age:max_age:warning:inactive:account_expiry:reservedEvery colon is structurally significant. A blank field is not automatically equivalent to zero. Its meaning depends on the field. Preserve the field count and the colon positions.
/etc/shadow Field Reference
The Password Field
The second field can have several forms. A usable password normally appears as a modular crypt password string. This format uses dollar signs to identify the algorithm and parameters, followed by salt and hash data.
Common identifiers include $1$ for MD5 crypt, $5$ for SHA-256 crypt, and $6$ for SHA-512 crypt. Systems using yescrypt commonly use an identifier such as $y$, where supported. Exact identifiers, accepted formats, and default algorithms depend on the distribution and its crypt library and PAM configuration.
A conceptual modular crypt value might look like $6$settings$saltdatatogetherwithhashdata. The prefix identifies the scheme and may encode settings such as cost. The salt separates otherwise identical passwords, while the remaining data represents the derived hash.
Password Field States
Password-Aging Fields
Password aging is policy controlling when passwords may be changed, when they expire, and when warnings appear. The day-count fields use the Unix epoch, which begins on 1970-01-01.
Last Change
The last-change field is an integer count of days since the epoch. It is not a timestamp in seconds. For example, day 20000 corresponds to 2024-10-04.
Minimum and Maximum Age
A minimum age of 0 allows an immediate password change. A minimum age of 1 requires one day to pass before another change.
The maximum age is the number of days after the last change when the password expires. A maximum age of 90 means the password reaches its expiration point 90 days after the last-change date. Values such as 99999 are commonly treated as effectively nonexpiring, but administrators should follow the distribution's policy.
Warning and Inactivity
The warning field specifies how many days before expiration the user should receive warnings. The inactivity field specifies the grace period after password expiration. When that grace period ends, password-authenticated access can be disabled.
An empty inactivity field is not the same as a numeric value such as 0 or 30. The exact behavior should be interpreted using the system's shadow implementation and account-management tools.
Account Expiration
The account-expiration field is an absolute epoch-day count. Once that date passes, the account can be disabled even if its password was recently changed and has not reached maximum age. This is different from password expiration, which concerns the password's permitted lifetime.
Password Expiration Versus Account Expiration
Effective login behavior can also be affected by PAM modules, account lock state, SSH configuration, remote identity providers, SSSD, LDAP, Active Directory, containers, and application-specific authentication.
Reading a Fictional Entry Safely
Consider this deliberately fictional record. The password value is a placeholder, not a usable credential or a copied hash:
analyst:$6$REDACTED$NOT_A_REAL_HASH:20000:0:90:14:30:20150:Interpret the nine positions as follows:
- Login name:
analyst. - Password field: A fictional SHA-512-crypt-style placeholder beginning with
$6$. It must not be treated as a real hash. - Last change: Day
20000, which is 2024-10-04. - Minimum age:
0, so the password may be changed immediately. - Maximum age:
90days. - Warning:
14days before expiration. - Inactivity:
30days after password expiration. - Account expiration: Day
20150, which is 2025-03-03. - Reserved: Blank, which is appropriate for the unused standard field.
The password expires on 2025-01-02: 2024-10-04 plus 90 days. The warning period begins on 2024-12-19, 14 days before expiration. If the password remains expired, the 30-day inactivity interval reaches its threshold on 2025-02-01. The account-expiration date, 2025-03-03, is an independent later cutoff.
Comparing Two Policies
An interactive user might have minimum age 0, maximum age 90, warning 14, and inactivity 30. A service account might instead have a locked password field because it is intended to use a service credential, certificate, token, or another noninteractive mechanism. Locking the password does not automatically disable every other authentication path.
Administrative Inspection and Management
Shadow data should be inspected narrowly and privately. Avoid placing output containing hashes in shell history, shared terminals, logs, screenshots, or support tickets.
Inspecting the Configured Account Source
getent shadow uses NSS (Name Service Switch), so it can obtain shadow information from configured sources beyond the local file. Restrict the query to one account:
sudo getent shadow USERNAMENSS may be connected to local files, LDAP, SSSD, or other providers. Therefore, a result from getent is not necessarily a line from the local /etc/shadow.
Readable Aging Information
Use chage to view policy without manually converting epoch-day values:
sudo chage -l USERNAMEFor example, set an example aging policy with:
sudo chage -m 1 -M 90 -W 14 -I 30 USERNAMESet an absolute account expiration date with:
sudo chage -E YYYY-MM-DD USERNAMEPassword and Lock Management
Use passwd to set or reset a password:
sudo passwd USERNAMELock or unlock password-based authentication with:
sudo passwd -l USERNAME
sudo passwd -u USERNAMEUnlock only when a valid password hash exists and restoring password authentication is authorized. The -l operation does not necessarily disable SSH keys or other authentication methods.
Using usermod
usermod provides another administrative interface for account expiration and post-password-expiration inactivity:
sudo usermod -e YYYY-MM-DD -f 30 USERNAMEOptions and behavior can vary slightly by implementation, so verify the result with chage -l.
When Direct Editing Is Unavoidable
If a documented recovery procedure requires direct editing, use the purpose-built editor workflow:
sudo vipw -svipw -s is safer than opening the file with a general editor because it provides locking and validation appropriate to account databases. Still make a verified backup, preserve all nine fields and separators, and have a tested recovery path before changing a privileged account.
Defaults and Policy Layers
Some distributions define default aging values in /etc/login.defs. These defaults commonly influence newly created accounts; changing them does not necessarily update existing accounts.
PAM configuration under /etc/pam.d/ influences password quality, expiration handling, empty-password behavior, and authentication outcomes. Do not apply blanket PAM edits: module names, file paths, and policy semantics vary by distribution.
Operational Cautions
- Do not manually alter a hash field unless there is a documented recovery procedure and a verified backup.
- Never remove or add colons casually. A malformed field count can prevent logins.
- Do not replace blank fields with zero without understanding the field-specific meaning.
- Use a maintenance console or tested recovery path before changing access policies for a privileged account.
- Test changes with a noncritical account before ending a maintenance session.
- Changing local
/etc/shadowmay not affect users authenticated through LDAP, Active Directory, SSSD, containers, or another external identity system.
Troubleshooting Common Problems
A User Must Change a Password or Cannot Use the Current Password
Likely causes include a reached maximum age, an administrator-forced expiration, or centralized PAM or directory policy. Start with:
sudo chage -l USERNAME
getent passwd USERNAMEDetermine whether the account is local, check applicable NSS or SSSD configuration, and review relevant authentication logs. Use passwd or chage to resolve the issue only after confirming the intended policy.
Password Login Fails After passwd -l
The password field may now contain a lock marker. Check the state with:
sudo passwd -S USERNAMEAlso check whether SSH keys or other authentication methods remain enabled. Use sudo passwd -u USERNAME only when password authentication should be restored. For full access restriction, use the appropriate account-expiration, shell, SSH, authorization, or service-specific controls.
An Account Is Disabled Despite a Recent Password Change
Check chage -l USERNAME. An absolute account-expiration date may have passed, a post-expiration inactivity interval may have elapsed, or a directory service may be applying a separate policy. Adjust the relevant setting only if continued access is authorized.
A Manual Edit Prevents Logins
Common causes include a moved colon, invalid date field, corrupted hash marker, or changed ownership and permissions. From a privileged console, compare the structure with a known-good local record, inspect metadata, and review authentication logs:
sudo stat -c '%A %U:%G %n' /etc/shadowRestore from a verified backup or repair through vipw -s. Validate access with a noncritical account before closing the maintenance session.
Exam-Relevant Notes
/etc/passwdis primarily identity data;/etc/shadowprotects password hashes and aging data.- Shadow passwords are one-way hashes, not reversibly encrypted passwords.
- The nine fields are colon-separated and ordered; blank fields have field-specific meanings.
- Epoch-day values count from 1970-01-01.
- Password expiration and account expiration are different events.
- A lock marker blocks ordinary password authentication but does not guarantee that every authentication method is disabled.
- NSS determines where account information comes from, while PAM commonly enforces authentication and account policy.
- Use
passwd,chage,usermod, andvipw -srather than casual manual edits.
For related account identity information, see the Linux account-file format lesson.