diff options
| author | Oleksandr Kuchmystyi <o.kuchmystyi@vyos.io> | 2026-06-15 17:00:56 +0300 |
|---|---|---|
| committer | Oleksandr Kuchmystyi <o.kuchmystyi@vyos.io> | 2026-06-15 18:24:03 +0300 |
| commit | e3b946e34b109406f38bfa5f78eb9a2ec7502bc9 (patch) | |
| tree | 4eaf914ef133ff194d8c4a900a9bfbd7328087c5 /src | |
| parent | 62e5ca63f15809408bfcb8f10332d5b771622a4e (diff) | |
| download | vyos-1x-e3b946e34b109406f38bfa5f78eb9a2ec7502bc9.tar.gz vyos-1x-e3b946e34b109406f38bfa5f78eb9a2ec7502bc9.zip | |
password-reset: T8985: Fix unbounded `sed` ranges corrupting other user blocks
`sed` ranges keyed on a field name (`plaintext-password`, `encrypted-password`,
`authentication {`) are not bounded to the target user's block. When the
field is absent the range stays open past the user's closing brace and
matches the first occurrence of that field in a later account.
Diffstat (limited to 'src')
| -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 } |
