pyinfra-dev / pyinfra

pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands.
https://pyinfra.com
MIT License
3.71k stars 359 forks source link

The sudo password doesn't seem to be properly escaped #1103

Open herr-felix opened 1 month ago

herr-felix commented 1 month ago

Describe the bug

A sudo password containing a semicolon (;) is and read correctly. The part after the ; is read as another command by the shell.

To Reproduce

With a file demo.py containing:

from pyinfra.operations import server
server.shell("echo zoo", _sudo=True, _sudo_password="asdf;ghjk")

And then running pyinfra -y @local demo.py.

Results in:

--> Loading config...
--> Loading inventory...
--> Connecting to hosts...
    [@local] Connected

--> Preparing operations...
--> Preparing Operations...
    Loading: demo.py
    [@local] Ready: demo.py

--> Skipping change detection
--> Beginning operation run...
--> Starting operation: server.shell (echo zoo)
[@local] >>> env SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-rn5Vra4Gl1Ys *** sudo -H -A -k sh -c 'echo zoo'
...[all my env dumped]...
[@local] PYINFRA_SUDO_PASSWORD=asdf
[@local] /bin/sh: line 1: ghjk: command not found
    [@local] Error: executed 0 commands

--> Disconnecting from hosts...
--> pyinfra error: No hosts remaining!
pyinfra -y @docker/d9b8dc0bb6a1 demo.py
--> Loading config...
--> Loading inventory...
--> Connecting to hosts...
    [@docker/d9b8dc0bb6a1] Connected

--> Preparing operations...
--> Preparing Operations...
    Loading: demo.py
    [@docker/d9b8dc0bb6a1] Ready: demo.py

--> Skipping change detection
--> Beginning operation run...
--> Starting operation: server.shell (echo zoo)
    [@docker/d9b8dc0bb6a1] HOSTNAME=d9b8dc0bb6a1
    [@docker/d9b8dc0bb6a1] HOME=/root
    [@docker/d9b8dc0bb6a1] PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [@docker/d9b8dc0bb6a1] PWD=/
    [@docker/d9b8dc0bb6a1] SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-zoLJuvakPyox
    [@docker/d9b8dc0bb6a1] PYINFRA_SUDO_PASSWORD=asdf
    [@docker/d9b8dc0bb6a1] sh: 1: ghjk: not found
    [@docker/d9b8dc0bb6a1] Error: executed 0 commands

--> Disconnecting from hosts...
    [@docker/d9b8dc0bb6a1] docker build complete, container left running: d9b8dc0bb6a1

--> pyinfra error: No hosts remaining!

Expected behavior

I expect the ; not affecting the use of the sudo password.

Meta

--> Connecting to hosts... [@local] Connected [pyinfra.api.state] Activating host: @local

--> Preparing operations... --> Preparing Operations... Loading: demo.py [pyinfra.api.operation] Adding operation, {'server.shell'}, opOrder=(0, 3), opHash=cedda09f9ebcba03bb3a36b21a0111fc8b7c3ec0 [@local] Ready: demo.py

--> Skipping change detection --> Beginning operation run... --> Starting operation: server.shell (echo zoo) [pyinfra.api.operations] Starting operation {'server.shell'} on @local

[pyinfra.connectors.local] --> Running command on localhost: sh -c ' temp=$(mktemp "${TMPDIR:=/tmp}/pyinfra-sudo-askpass-XXXXXXXXXXXX") cat >"$temp"<<'"'"'EOF'"'"'

!/bin/sh

printf '"'"'%s\n'"'"' "$PYINFRA_SUDO_PASSWORD" EOF chmod 755 "$temp" echo "$temp" ' [pyinfra.connectors.util] --> Waiting for exit status... [pyinfra.connectors.util] --> Command exit status: 0 [pyinfra.connectors.local] --> Running command on localhost: env SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-RNKJiA1Wg1RE *** sudo -H -A -k sh -c 'echo zoo' [pyinfra.connectors.util] --> Waiting for exit status... [pyinfra.connectors.util] --> Command exit status: 127 ...... [@local] PYINFRA_SUDO_PASSWORD=asdf [@local] /bin/sh: line 1: ghjk: command not found [@local] Error: executed 0 commands [pyinfra.api.state] Failing hosts: @local

--> Disconnecting from hosts... --> pyinfra error: No hosts remaining!



Thank you very much!
sudoBash418 commented 1 month ago

I think this should be fixed by https://github.com/pyinfra-dev/pyinfra/commit/9b6c214effb75b4c485b3766a135bae26029edbd? (not yet released)