Bugzilla – Bug 413
Unexpected change in quoting behaviour with -i flag
Last modified: 2010-06-29 11:30:16 MDT
Seen: $ sudo ls -l "thing not here" ls: cannot access thing not here: No such file or directory $ sudo -i ls -l "thing not here" ls: cannot access thing: No such file or directory ls: cannot access not: No such file or directory ls: cannot access here: No such file or directory Expected: Seen: $ sudo ls -l "thing not here" ls: cannot access thing not here: No such file or directory $ sudo -i ls -l "thing not here" ls: cannot access thing not here: No such file or directory I can't see anything that suggests '-i' would affect the use of arguments, just the environment in which the command runs. [I would consider anything that could possibly run the wrong command in 'sudo' a high priority bug.]
The problem is that the shell removes the quotes when the command is executed so when sudo joins the exec arguments it effectively runs: sh -c "ls -l thing not here" If you do: sudo -i \"thing not here\" you get the expected behavior. I'll change the way the arguments are handled to quote ones with spaces which should resolve the issue.
Created attachment 276 [details] Patch to quote non alphanumerics when running a command via "sudo -s" or "sudo -i" I've attached a patch that fixes the problem.
(In reply to comment #1) > The problem is that the shell removes the quotes when the command is executed > so when sudo joins the exec arguments it effectively runs: > > sh -c "ls -l thing not here" > > If you do: sudo -i \"thing not here\" > > you get the expected behavior. I'll change the way the arguments are handled > to quote ones with spaces which should resolve the issue. You better should let the shell do this job itself. Instead of executing sh -c "ls -l thing not here" you just execute sh -c 'ls $@' "thing not here" This doesn't require any wild argument-string modification, the user provided arguments remain the same. The only thing you need to do is to append the string '$@' to the command to be executed as the second argument of sh and then use the elements in argv as following arguments.
That's not possible as the shell is not running at that point; there is nothing to expand "$@".
(In reply to comment #4) > That's not possible as the shell is not running at that point; there is nothing > to expand "$@". I'm sorry, I see this wasn't clear. The $@ must not be expanded, it must be passed to the shell within the command string. The shell will then expand it to the arguments that follow. Just a detail though: when using the form sh -c cmd args... the arguments are assigned to the positional parameters starting from 0, so you the user arguments need to start one further. So this is what you need to execute: sh -c 'usercmd "$@"' usercmd userarg1 userarg2 ...
Just try it out, type this into your terminal: sh -c 'ls "$@"' ls bla "bla bla"
Unfortunately, that is bourne-shell specific so it won't work for all shells. One possibility would be to have a whitelist of "good" shells to use the "$@" trick for and then just quote non-alphanumerics for anything else.
That's right so it also works in korn shell and all POSIX compliant shells. In [t]csh you can use $argv[*]:q instead of "$@". Watch out though, when using the form csh -c cmd args... positional parameters are assigned starting from 1 and not from 0 as with sh, so you need to change the command line [1] or skip the first argument [2]. The latter option avoids you to change your parameter array for exec with respect to the sh-form. [1] csh -c 'usercmd $argv[*]:q' userarg1 userarg2 ... [2] csh -c 'usercmd $argv[2-]:q' usercmd userarg1 userarg2 ...
Any quoting you do is technically shell-specific as well, as is use of the '-c' flag, which need not be supported by the shell the target user has chosen. (Given that a shell binary can be anything.)
(In reply to comment #9) Isn't this problem related to the -i option? So if you want to simulate an initial login, this should definitely be done by a real shell with the capability to launch other programs with some arguments. So you may just limit the -i option to known shells. The user can then do all the other stuff manually without the -i option.