3

From https://stackoverflow.com/a/29400598/156458

The other solutions I've seen here so far are based on some system definitions, but it's in fact possible to have sudo use the current PATH (with the env command) and/or the rest of the environment (with the -E option) just by invoking it right:

sudo -E env "PATH=$PATH" <command> [arguments]

In fact, one can make an alias out of it:

alias mysudo='sudo -E env "PATH=$PATH"'

(It's also possible to name the alias itself sudo, replacing the original sudo.)

Given that

-E, --preserve-env Indicates to the security policy that the user wishes to preserve their existing environment variables. The security policy may return an error if the user does not have permission to preserve the environment.

I was wondering why the following doesn't work

sudo -E <command> [arguments]

?

Given that "PATH=$PATH" <command> [arguments] is also a command, I was wondering why the following doesn't work:

sudo  "PATH=$PATH" <command> [arguments]

?

Thanks.

Tim
  • 101,790
  • 1
  • Why the downvotes? – Stéphane Chazelas May 09 '18 at 12:52
  • 4
    I haven't voted, but I could imagine a reader asking "What do you mean by doesn't work?" - Does sudo fail? Does the command not get the updated environment? Does it not match a sudoers entry? I think it'd also be useful to include the sudo configuration here regarding whitelist/blacklist/keep settings. – Jeff Schaller May 09 '18 at 13:08
  • Your statement, "Given that "PATH=$PATH" <command> [arguments] is also a command..." is a false premise. It's not a command; it's an environment variable assignment followed by a command. Quoting aside, you could try sudo bash -c "PATH=... command args...". Just bear in mind that command would still need to be in your default sudo value of $PATH or else you'd need to use an explicit /path/to/command – Chris Davies May 09 '18 at 22:25

1 Answers1

11
sudo -E <command> [arguments]

doesn’t work in your case because Debian defines secure_path in /etc/defaults, which overrides the value of PATH even with -E.

sudo  "PATH=$PATH" <command> [arguments]

should work because PATH=$PATH is recognised and processed by sudo. In my case sudo "PATH=$PATH" env shows my current PATH value. (Note that PATH=$PATH <command> isn’t a universally-recognised command; it corresponds to a construct which is recognised by the shell and by sudo, but not necessarily in other contexts.).

However sudo itself doesn't use that $PATH to look the <command> up and still uses the secure_path.

sudo -E env "PATH=$PATH" <command> [arguments]

works because "PATH=$PATH" stores the current value of PATH in the command as seen by sudo and then env; sudo replaces the value of PATH as given to env in its environment, but env then reads the value from its arguments to build the environment for <command>.

And here, the env command is looked-up by sudo in secure_path, but env itself looks <command> up in the provided $PATH.

Stephen Kitt
  • 434,908
  • sudo --preserve-env=PATH is better than sudo -E env "PATH=$PATH" (I used --preserve-env instead of -E, because I prefer long options for readability when I write scripts; it is the same option) – artyom.razinov Feb 16 '24 at 13:09
  • @artyom.razinov here, -E isn’t usable, as explained in the first paragraph. Redefining PATH is a workaround — it’s handled by env, not sudo, and as a result avoids the PATH restrictions imposed by sudo. (I can’t remember why I wrote sudo -E env "PATH=$PATH"; the effect should be the same with sudo env "PATH=$PATH".) – Stephen Kitt Feb 16 '24 at 13:17
  • sudo --preserve-env=PATH still seems better than sudo env "PATH=$PATH". First, it's the option of sudo, second, you don't need shell interpreter for this, this is just an argument and not a literal with code in sh/bash/zsh like $PATH. Also if you use something like ssh ... sudo env "PATH=$PATH" ... you can get unexpected result ($PATH will be from a local machine and not from the remote machine). I just wanted to give alternative that I just used in code. – artyom.razinov Feb 16 '24 at 13:26
  • @artyom.razinov you’re missing the point that -E is ignored in the configuration discussed here (because of secure_path) — or rather, that PATH is set by sudo to the value defined by secure_path, so the only way to override it is to set it again afterwards (using env here). – Stephen Kitt Feb 16 '24 at 13:30
  • You are missing my point. --preserve-env=PATH is almost equivalent to -E /usr/bin/env "PATH=$PATH" as PATH is not overwritten by secure_path in both cases. At least on Mac OS. My point is that I want to provide an alternative that can be better in some cases. For example PATH=itworks; /usr/bin/sudo -E /usr/bin/env "PATH=$PATH" /usr/bin/printenv PATH is equivalent to PATH=itworks; /usr/bin/sudo --preserve-env=PATH /usr/bin/printenv PATH. However, if you remove ; it stops being equivalent. Because $PATH takes value from current shell and in some cases it can lead to errors. – artyom.razinov Feb 28 '24 at 14:27
  • @artyom.razinov again, in the context of this question, -E isn’t usable, with or without arguments (the OP explicitly mentions that it doesn’t work). If -E was usable, then yes, -E is preferable, but that isn’t the case here (and that’s the entire premise of the question — if -E did work, there would be no question). – Stephen Kitt Feb 28 '24 at 16:48