Fixes the napalm-linux half of NetOrk/netork#1039. The netOrk half and #1074 come in a separate NetOrk PR.
_sudo typed echo '<password>' | sudo -S -p "" <command> into netmiko's interactive shell. Two consequences:
bash kept the line in its history, so every poll wrote the sudo password into the login user's ~/.bash_history (121 lines on one host);
while the command ran, the password was in the process list for every local user.
Change
_sudo, _sudo_status, and _run_privileged with a password now run on an exec channel, like run_command(privileged=True):
the password reaches sudo -S on stdin, and there is no PTY to echo it;
the script starts with exec </dev/null, so a non-prompting sudo leaves the password unread.
The whole command runs as root in one sh -c. Before, only the part up to the first ;, && or | did, so e.g. mv … && chown root:root failed its chown.
The exit status comes from the channel; paramiko's -1 maps to None ("unknown").
The interactive session switches its history off before its first command: unset HISTFILE; set +o history.
get_vpn_tunnels with a password reads wg show all dump from the exec channel. The temp file that briefly held the private keys is no longer used.
Without a sudo password nothing changes: sudo -n still goes through the PTY, and it carries no secret.
Callers checked: every _sudo command is POSIX sh (no bashisms). napalm-openmediavault and napalm-qnap-qts inherit the change and pass their suites against it.
Tests: new tests/test_sudo_off_the_command_line.py (19 tests), which checks that the history-off line comes first and uses a fake channel that refuses any line containing the password. Full suite: 160 passed.
Root writes no longer touch a fixed /tmp path (second commit). With the whole line running as root, mv /tmp/netork_snmpd.conf … && chown root:root … && chmod 644 … would have let a local user plant a symlink at the fixed path and make root's chown and chmod follow it, e.g. to /etc/shadow. The same applied to 00proxy.
_install_file_as_root stages the content unprivileged in a fresh mktemp file (umask 077) and checks the path it gets back.
Root then runs install -m 644 -o root -g root into a new file and mvs it over the target. No chown/chmod runs, nothing follows a symlink, and nothing runs as root when staging failed.
get_vpn_tunnels always reads from the exec channel. The predictable /tmp/.netork_wg_<hash> file is gone.
New tests/test_staged_root_writes.py (14 tests, including planted symlinks at the old paths). Full suite: 174 passed; OMV and QNAP suites pass against it.
Fixes the napalm-linux half of NetOrk/netork#1039. The netOrk half and #1074 come in a separate NetOrk PR.
`_sudo` typed `echo '<password>' | sudo -S -p "" <command>` into netmiko's interactive shell. Two consequences:
- bash kept the line in its history, so every poll wrote the sudo password into the login user's `~/.bash_history` (121 lines on one host);
- while the command ran, the password was in the process list for every local user.
**Change**
- `_sudo`, `_sudo_status`, and `_run_privileged` with a password now run on an exec channel, like `run_command(privileged=True)`:
- the password reaches `sudo -S` on stdin, and there is no PTY to echo it;
- the script starts with `exec </dev/null`, so a non-prompting sudo leaves the password unread.
- The whole command runs as root in one `sh -c`. Before, only the part up to the first `;`, `&&` or `|` did, so e.g. `mv … && chown root:root` failed its chown.
- The exit status comes from the channel; paramiko's -1 maps to `None` ("unknown").
- The interactive session switches its history off before its first command: ` unset HISTFILE; set +o history`.
- `get_vpn_tunnels` with a password reads `wg show all dump` from the exec channel. The temp file that briefly held the private keys is no longer used.
- Without a sudo password nothing changes: `sudo -n` still goes through the PTY, and it carries no secret.
**Callers checked:** every `_sudo` command is POSIX `sh` (no bashisms). napalm-openmediavault and napalm-qnap-qts inherit the change and pass their suites against it.
**Tests:** new `tests/test_sudo_off_the_command_line.py` (19 tests), which checks that the history-off line comes first and uses a fake channel that refuses any line containing the password. Full suite: 160 passed.
**Root writes no longer touch a fixed /tmp path** (second commit). With the whole line running as root, `mv /tmp/netork_snmpd.conf … && chown root:root … && chmod 644 …` would have let a local user plant a symlink at the fixed path and make root's chown and chmod follow it, e.g. to `/etc/shadow`. The same applied to 00proxy.
- `_install_file_as_root` stages the content unprivileged in a fresh `mktemp` file (`umask 077`) and checks the path it gets back.
- Root then runs `install -m 644 -o root -g root` into a new file and `mv`s it over the target. No `chown`/`chmod` runs, nothing follows a symlink, and nothing runs as root when staging failed.
- `get_vpn_tunnels` always reads from the exec channel. The predictable `/tmp/.netork_wg_<hash>` file is gone.
- New `tests/test_staged_root_writes.py` (14 tests, including planted symlinks at the old paths). Full suite: 174 passed; OMV and QNAP suites pass against it.
_sudo typed `echo '<password>' | sudo -S -p "" <command>` into netmiko's
interactive shell. bash kept it in its history, so every poll wrote the sudo
password into the login user's ~/.bash_history, and while the command ran it
was in the process list for every local user (NetOrk/netork#1039).
_sudo, _sudo_status and _run_privileged with a password now run on an exec
channel like run_command(privileged=True): the password reaches sudo -S on
stdin, there is no PTY to echo it, and the script starts with
`exec </dev/null` so a non-prompting sudo leaves it unread. The whole
command runs as root in one sh -c - before, only the part up to the first
`;`, `&&` or `|` did. The exit status comes from the channel.
The interactive session switches its history off before its first command.
get_vpn_tunnels with a password reads `wg show all dump` from the exec
channel instead of a temp file that held the private keys.
Now that a whole _sudo line runs as root, `mv /tmp/netork_snmpd.conf
/etc/snmp/snmpd.conf && chown root:root … && chmod 644 …` would have let a
local user plant a symlink at the fixed /tmp path and have root's chown and
chmod follow it (e.g. to /etc/shadow). The same held for 00proxy.
_install_file_as_root stages the content unprivileged in a fresh mktemp file
(umask 077), checks the path it got back, and root installs it as a new
regular file next to the target and renames it over: nothing root runs
follows a symlink or changes the owner or mode of an existing path. Nothing
runs as root when staging failed.
get_vpn_tunnels always reads `wg show all dump` from the exec channel; the
predictable /tmp/.netork_wg_<hash> file holding the private keys is gone.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes the napalm-linux half of NetOrk/netork#1039. The netOrk half and #1074 come in a separate NetOrk PR.
_sudotypedecho '<password>' | sudo -S -p "" <command>into netmiko's interactive shell. Two consequences:~/.bash_history(121 lines on one host);Change
_sudo,_sudo_status, and_run_privilegedwith a password now run on an exec channel, likerun_command(privileged=True):sudo -Son stdin, and there is no PTY to echo it;exec </dev/null, so a non-prompting sudo leaves the password unread.sh -c. Before, only the part up to the first;,&&or|did, so e.g.mv … && chown root:rootfailed its chown.None("unknown").unset HISTFILE; set +o history.get_vpn_tunnelswith a password readswg show all dumpfrom the exec channel. The temp file that briefly held the private keys is no longer used.sudo -nstill goes through the PTY, and it carries no secret.Callers checked: every
_sudocommand is POSIXsh(no bashisms). napalm-openmediavault and napalm-qnap-qts inherit the change and pass their suites against it.Tests: new
tests/test_sudo_off_the_command_line.py(19 tests), which checks that the history-off line comes first and uses a fake channel that refuses any line containing the password. Full suite: 160 passed.Root writes no longer touch a fixed /tmp path (second commit). With the whole line running as root,
mv /tmp/netork_snmpd.conf … && chown root:root … && chmod 644 …would have let a local user plant a symlink at the fixed path and make root's chown and chmod follow it, e.g. to/etc/shadow. The same applied to 00proxy._install_file_as_rootstages the content unprivileged in a freshmktempfile (umask 077) and checks the path it gets back.install -m 644 -o root -g rootinto a new file andmvs it over the target. Nochown/chmodruns, nothing follows a symlink, and nothing runs as root when staging failed.get_vpn_tunnelsalways reads from the exec channel. The predictable/tmp/.netork_wg_<hash>file is gone.tests/test_staged_root_writes.py(14 tests, including planted symlinks at the old paths). Full suite: 174 passed; OMV and QNAP suites pass against it.