diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-06-18 16:09:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-18 16:09:57 +0200 |
| commit | 1057fca4ebffbce36a5f31e6ff1524766cf7fe3b (patch) | |
| tree | 63b88cb331c8e550baca7e7ce12dc8fe78293a64 | |
| parent | abb323b83b55f0929151d96f5d98dbd3741a55eb (diff) | |
| parent | e3b946e34b109406f38bfa5f78eb9a2ec7502bc9 (diff) | |
| download | vyos-1x-1057fca4ebffbce36a5f31e6ff1524766cf7fe3b.tar.gz vyos-1x-1057fca4ebffbce36a5f31e6ff1524766cf7fe3b.zip | |
Merge pull request #5273 from alexandr-san4ez/T8985-rolling
password-reset: T8985: Fix unbounded `sed` ranges corrupting other user blocks
| -rwxr-xr-x | src/system/standalone_root_pw_reset | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/src/system/standalone_root_pw_reset b/src/system/standalone_root_pw_reset index aa712ad52..4cd4b98d4 100755 --- a/src/system/standalone_root_pw_reset +++ b/src/system/standalone_root_pw_reset @@ -27,7 +27,11 @@ CF=/opt/vyatta/etc/config/config.boot ADMIN=vyos set_encrypted_password() { - local user=$1 epwd=$2 file=$3 + local user_raw=$1 epwd=$2 file=$3 + local user + + # Escape the username before using it in awk/sed regexes + user=$(printf '%s' "$user_raw" | sed -e 's/\./\\&/g') # Check if encrypted-password exists within this specific user's block if awk "/ user $user \{/{f=1} f && /encrypted-password/{found=1; exit} f && /^ }/{exit} END{exit !found}" "$file"; then @@ -35,15 +39,41 @@ set_encrypted_password() { sed -i \ -e "/ user $user {/,/encrypted-password/s/encrypted-password .*\$/encrypted-password \"$epwd\"/" "$file" else - # Insert encrypted-password after plaintext-password - sed -i \ - -e "/ user $user {/,/plaintext-password/s/\(plaintext-password .*\)\$/\1\n encrypted-password \"$epwd\"/" "$file" + # Key-only account: no encrypted-password or plaintext-password line exists + # in this user's block (e.g. authentication via SSH key only). + if awk "/ user $user \{/{f=1} f && /authentication \{/{found=1; exit} f && /^ \}/{exit} END{exit !found}" "$file"; then + # 'authentication' block exists - insert encrypted-password inside it + sed -i \ + -e "/ user $user {/,/authentication {/s/\(authentication {\)\$/\1\n encrypted-password \"$epwd\"/" "$file" + else + # No authentication block at all. Without this branch the sed range + # above would overrun the block boundary and corrupt a later account's + # authentication block. Build the section from scratch instead. + sed -i \ + -e "/ user $user {/a\\ + authentication {\\ + encrypted-password \"$epwd\"\\ + plaintext-password \"\"\\ + }" "$file" + fi fi } clear_plaintext_password() { - sed -i \ - -e "/ user $1 {/,/plaintext-password/s/plaintext-password .*\$/plaintext-password \"\"/" $2 + local user_raw=$1 file=$2 + local user + + # Escape the username before using it in awk/sed regexes + user=$(printf '%s' "$user_raw" | sed -e 's/\./\\&/g') + + # Only clear if plaintext-password exists within this specific user's block. + # Without this guard, if the user has no plaintext-password line the sed + # range never closes inside their block and spills into the next account + # that does have one, wiping that account's plaintext-password instead. + if awk "/ user $user \{/{f=1} f && /plaintext-password/{found=1; exit} f && /^ \}/{exit} END{exit !found}" "$file"; then + sed -i \ + -e "/ user $user {/,/plaintext-password/s/plaintext-password .*\$/plaintext-password \"\"/" "$file" + fi } |
