Created
June 6, 2025 21:42
-
-
Save VSharapov/e85dabfdc948084fcc2ab198e669d7ed to your computer and use it in GitHub Desktop.
If there's no `passwd` or `chpasswd` try this jank
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| set -eu | |
| # DEBUG=true | |
| DEBUG=false | |
| if $DEBUG; then | |
| trap 'echo "# $BASH_COMMAND";read' DEBUG | |
| fi | |
| PAGER=${PAGER:-more} | |
| for cmd in sed openssl diff $PAGER; do | |
| if ! command -v "$cmd" >/dev/null 2>&1; then | |
| echo "Missing required command: $cmd" >&2 | |
| exit 1 | |
| fi | |
| done | |
| if [ "$(id -u)" -ne 0 ]; then | |
| echo "You must run this as root." >&2 | |
| exit 1 | |
| fi | |
| if ! cat /etc/shadow > /dev/null; then | |
| echo "Cannot read /etc/shadow" >&2 | |
| exit 1 | |
| fi | |
| printf "What user are we messing with? " >&2 | |
| read -r target_user | |
| shadow_line=$(grep "^$target_user:" /etc/shadow || true) | |
| if [ -z "$shadow_line" ]; then | |
| echo "User '$target_user' not found in /etc/shadow" >&2 | |
| exit 1 | |
| fi | |
| IFS='$' read -r _ algo salt current_hash <<EOF | |
| $(echo "$shadow_line" | cut -d: -f2) | |
| EOF | |
| if ! [ -n "$algo" ] && [ -n "$salt" ] && [ -n "$current_hash" ]; then | |
| echo "Failed to extract hash components." >&2 | |
| echo "shadow_line: ${shadow_line:-"unset"}" | |
| echo "algo: ${algo:-"unset"}" | |
| echo "salt: ${salt:-"unset"}" | |
| echo "current_hash: ${current_hash:-"unset"}" | |
| exit 1 | |
| fi | |
| echo "Sanity check: if you know the current password, enter it now." | |
| echo "Or press Enter to skip:" | |
| read -r current_pw | |
| if [ -n "$current_pw" ]; then | |
| computed_hash=$(openssl passwd -$algo -salt "$salt" "$current_pw") | |
| expected_output="\$$algo\$$salt\$$current_hash" | |
| if [ "$computed_hash" != "$expected_output" ]; then | |
| echo "Password does not match!" >&2 | |
| echo "Computed from your input:" >&2 | |
| echo "$computed_hash" >&2 | |
| echo "What appears in /etc/shadow:" >&2 | |
| echo "$expected_output" >&2 | |
| echo "The full line in /etc/shadow:" >&2 | |
| echo "$shadow_line" >&2 | |
| exit 1 | |
| else | |
| echo "Password verified." | |
| fi | |
| else | |
| echo "You have FOOLISHLY chosen to skip password verification." >&2 | |
| fi | |
| printf "Enter new password: " >&2 | |
| read -r new_pw | |
| # openssl will output the dollar signs, algorithm, salt, and hash. | |
| new_full_hash=$(openssl passwd -$algo -salt "$salt" "$new_pw") | |
| # Assigning to a variable seems to turn newlines into spaces, I'm sure it could be fixed, but this works fine. | |
| cat /etc/shadow | sed "s#^$target_user:\$$algo\$$salt\$$current_hash:#$target_user:$new_full_hash:#" > /etc/shadow.new && \ | |
| echo "Wrote /etc/shadow.new" >&2 | |
| echo "Here is a diff of the changes:" >&2 | |
| echo "---" >&2 | |
| diff /etc/shadow /etc/shadow.new | $PAGER | |
| echo "---" >&2 | |
| printf "Type 'lgtm' to apply changes (a backup will be made): " >&2 | |
| read -r confirm | |
| if [ "$confirm" != "lgtm" ]; then | |
| echo "Deleting /etc/shadow.new and aborting." >&2 | |
| rm /etc/shadow.new | |
| exit 1 | |
| fi | |
| echo "Applying changes..." >&2 | |
| cp /etc/shadow /etc/shadow.bak | |
| cat /etc/shadow.new > /etc/shadow | |
| rm /etc/shadow.new | |
| cat <<EOF | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| /!\ /etc/shadow updated /!\ | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| Test login now. If it fails, run: | |
| mv /etc/shadow.bak /etc/shadow | |
| If everything looks good, run: | |
| rm /etc/shadow.bak | |
| EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment