Safely Replace Linux Account Files with cppw and cpgr
cppw and cpgr copy a prepared file straight over /etc/passwd, /etc/group, /etc/shadow or /etc/gshadow, taking the correct lock as they go. These examples use the passwd package version 1:4.13+dfsg1-4ubuntu3.2 installed on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow 15 to 30 minutes, plus time to validate the source file properly. You need a root shell or equivalent permission to replace the system account database, a prepared file readable by that account, and a maintenance plan in case services or users are affected. This is a security-sensitive operation: never experiment against a live file, and never paste an untrusted path into a privileged command.
1. Check the installed command
First confirm which executable will run and read its built-in help. These checks are ordinary and change nothing:
$ command -v cppw
/usr/sbin/cppw
$ dpkg-query -W -f='${Package} ${Version}\n' passwd
passwd 1:4.13+dfsg1-4ubuntu3.2
$ cppw -h
Usage:
`cppw <file>' copys over /etc/passwd `cppw -s <file>' copys over /etc/shadow
`cpgr <file>' copys over /etc/group `cpgr -s <file>' copys over /etc/gshadow
That spelling in the help text comes straight from the installed program, typo and all. What matters is the command shape: one source file, with an optional -s switch. The manual documents no long options, so stick to the short forms shown here.
Checkpoint
Stop if command -v turns up an unexpected implementation, or the package version differs from the one in this guide. Read that system's own manual before trusting these examples on it.
2. Map the command to its destination
Pick the command based on which destination you actually intend to replace. Without -s, cppw copies its source to /etc/passwd and cpgr copies to /etc/group; with -s, each targets its shadow counterpart instead:
| Command | Destination | Typical contents |
|---|---|---|
cppw FILE | /etc/passwd | Account names, IDs, shells and home directories |
cpgr FILE | /etc/group | Group names, IDs and membership lists |
cppw -s FILE | /etc/shadow | Password hashes and password ageing data |
cpgr -s FILE | /etc/gshadow | Group administration and restricted group data |
cppw serves both password-file targets, and cpgr both group-file targets. Do not reach for -s just because the source file happens to be private; use it because the destination genuinely is the shadow file.
3. Prepare and inspect the source
cppw and cpgr are copy-with-lock tools, full stop: their manual page makes no promise about repairing malformed records or reconciling related files. Prepare the source with a tool that actually understands the account database, then inspect it before replacement, keeping the path explicit and quoted:
# SOURCE='/root/account-staging/passwd.new'
# test -r "$SOURCE" && printf 'readable: %s\n' "$SOURCE"
# pwck -r "$SOURCE"
readable: /root/account-staging/passwd.new
The exact options pwck accepts sit outside cppw's own contract, so use whatever validation tool and procedure suits the file format on your host; for a group file, reach for the corresponding group checker if it is installed. If validation reports an error, stop and fix the source rather than pressing on. Never use the copy command itself as a test of whether the data is safe.
Before touching /etc at all, take a timestamped backup through your normal privileged backup process, and record which source belongs to which destination. A backup of /etc/passwd does not stand in for a backup of /etc/shadow, and neither stands in for the group files.
4. Replace one file, with the correct privilege
Run only the mapping you checked in the previous step. This example replaces the password file from a prepared source and lets the program do its own documented locking:
# cppw /root/account-staging/passwd.new
There is normally no success message at all, so check the exit status straight away:
# printf 'cppw exit status: %s\n' "$?"
cppw exit status: 0
For a group file, reach for cpgr instead:
# cpgr /root/account-staging/group.new
# printf 'cpgr exit status: %s\n' "$?"
cpgr exit status: 0
Writing these destinations normally needs elevated privileges. Run the command as an ordinary user and expect a permission failure, not a partial workaround: do not make the destination world-writable, and do not weaken its ownership or mode just to get past the error.
5. Replace a shadow file only when that is the plan
-s changes the destination, not the input format or the underlying locking idea. Use it on purpose:
# cppw -s /root/account-staging/shadow.new
# printf 'shadow replacement exit status: %s\n' "$?"
shadow replacement exit status: 0
# cpgr -s /root/account-staging/gshadow.new
# printf 'gshadow replacement exit status: %s\n' "$?"
gshadow replacement exit status: 0
Shadow files hold authentication-sensitive data. Restrict access to the staging directory and remove temporary copies through your approved process once replacement is verified, and never include their contents in a support ticket or command transcript.
Warning
These commands change the system account database directly. A successful exit status only means the copy operation completed; it proves nothing about whether the source matches every related file, or whether logins and services will keep behaving as intended.
6. Verify the result and recover if needed
Run read-only checks once the copy is done. Compare the destination against the prepared source using a method that does not expose shadow contents to other users, and run the matching account-file checker:
# pwck -r
# grpck -r
# getent passwd example-user
# getent group example-group
Those getent lookups should show the expected records if those names exist in the active account source. Check whichever service or login path motivated the change in the first place, ideally with a test account. If the command failed, or validation turns up a problem, do not simply repeat it with a different random source.
There is no undo switch here. Recovery means running cppw or cpgr again with the known-good backup for the same destination, using -s for a shadow destination, then repeating the checks. If the account database is already inconsistent or authentication is already failing, use the host's documented recovery console or maintenance procedure and keep the original backup untouched.
Done means
- The installed package and command syntax were checked.
- The source file was prepared, readable and validated before the copy.
- The command and
-schoice matched the intended destination. - A privileged backup exists for each file changed.
- The command returned status 0 and post-change checks passed.
- You know which known-good source will restore the destination if the change must be reversed.