pyinfra icon indicating copy to clipboard operation
pyinfra copied to clipboard

Sudo fails to ask for a password if locale of remote system is not English

Open philippemilink opened this issue 1 year ago • 5 comments

Describe the bug

If remote system is configured with a locale different than English, sudo will fail to prompt for a password.

On remote system:

echo $LANG
fr_FR.UTF-8

Example of failing command:

pyinfra --debug-all -y 192.168.1.16 server.shell "echo foo" _sudo=true
--> Starting operation: server.shell (echo foo)
    [pyinfra.api.operations] Starting operation {'server.shell'} on 192.168.1.16
    [pyinfra.connectors.ssh] Running command on 192.168.1.16: (pty=False) sudo -H -n sh -c 'echo foo'
DEBUG:paramiko.transport:[chan 0] Max packet in: 32768 bytes
DEBUG:paramiko.transport:[chan 0] Max packet out: 32768 bytes
DEBUG:paramiko.transport:Secsh channel 0 opened.
DEBUG:paramiko.transport:[chan 0] Sesch channel 0 request ok
DEBUG:paramiko.transport:[chan 0] EOF received (0)
DEBUG:paramiko.transport:[chan 0] EOF sent (0)
    [pyinfra.connectors.ssh] Waiting for exit status...
    [pyinfra.connectors.ssh] Command exit status: 1
    [192.168.1.16] sudo: il est nécessaire de saisir un mot de passe
    [192.168.1.16] Error: executed 0 commands
    [pyinfra.api.state] Failing hosts: 192.168.1.16

The problem comes from this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L203

In this case, the remote system being in French, sudo prints sudo: il est nécessaire de saisir un mot de passe.

I "fixed" the bug by changing this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346

into

command_bits.extend(["LANG=C", "sudo", "-H"])

but I'm not sure whether this is the right fix.

Meta

Observed with Pip package 3.0b2.

I just spent this week-end testing Pyinfra, it looks promising! :+1:

philippemilink avatar Jun 09 '24 20:06 philippemilink

Can confirm that this is caused by pyinfra using string matching on the sudo output, which depends on the locale. Unfortunately, there's no option to set that string (the --prompt option only applies to interactive runs), and the exit code in this situation is 1.

Setting LANG=C is a good workaround. You should be able to pass it via the _env argument that all operations accept. You should be able to specify it once in the inventory data too.

xvello avatar Jun 10 '24 11:06 xvello

You should be able to pass it via the _env argument that all operations accept. You should be able to specify it once in the inventory data too.

No, because using _env puts the environment variables inside the sudo command (ie sudo LANG=C echo foo), while we need to set the environment variable for sudo (ie LANG=C sudo echo foo).

philippemilink avatar Jun 10 '24 19:06 philippemilink

Nice catch, definitely want to fix this! My worry with applying env everywhere is accidentally leaking into the sub command which may have unintended consequences..

Fizzadar avatar Jun 25 '24 06:06 Fizzadar

I also ran into this issue.

I "fixed" the bug by changing this line:

https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346

into

command_bits.extend(["LANG=C", "sudo", "-H"])

but I'm not sure whether this is the right fix.

This worked for me as well (de_DE.UTF-8).

My worry is that setting this might leak into the actual command:

sudo bash -c 'echo $LANG'
# => de_DE.UTF-8

LANG=C sudo bash -c 'echo $LANG'
# => C

This might break things if users of pyinfra match on the command output and the locale suddenly changes. Or am I getting things wrong? Environment variables should only be preserved when using -E, right?

simonhammes avatar Aug 11 '24 21:08 simonhammes

I also ran into this issue.

I "fixed" the bug by changing this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346

into

command_bits.extend(["LANG=C", "sudo", "-H"])

but I'm not sure whether this is the right fix.

This worked for me as well (de_DE.UTF-8).

My worry is that setting this might leak into the actual command:

sudo bash -c 'echo $LANG'
# => de_DE.UTF-8

LANG=C sudo bash -c 'echo $LANG'
# => C

This might break things if users of pyinfra match on the command output and the locale suddenly changes. Or am I getting things wrong? Environment variables should only be preserved when using -E, right?

This fix worked for me too. Also de_DE.UTF-8.

aZa1905 avatar Sep 02 '24 10:09 aZa1905