Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manual does not state exactly what is passed to the shell’s -c option for options --login and --shell #121

Closed
Rinzwind opened this issue Nov 20, 2021 · 2 comments

Comments

@Rinzwind
Copy link

Rinzwind commented Nov 20, 2021

The description of --login and --shell in the manual may need some clarification on what command (if any) is passed to the shell, it currently only says “If a command is specified, it is passed to the shell for execution via the shell's -c option”:

sudo/docs/sudo.man.in

Lines 442 to 454 in 7baee70

\fB\-i\fR, \fB\--login\fR
Run the shell specified by the target user's password database entry
as a login shell.
This means that login-specific resource files such as
\fI.profile\fR,
\fI.bash_profile\fR
or
\fI.login\fR
will be read by the shell.
If a command is specified, it is passed to the shell for execution
via the shell's
\fB\-c\fR
option.

sudo/docs/sudo.man.in

Lines 621 to 629 in 7baee70

\fB\-s\fR, \fB\--shell\fR
Run the shell specified by the
\fRSHELL\fR
environment variable if it is set or the shell specified by the
invoking user's password database entry.
If a command is specified, it is passed to the shell for execution
via the shell's
\fB\-c\fR
option.

Specifically, the escaping rules applied could use some clarification. I personally got a bit confused about this:

$ sudo --login echo $'\'$USER\''
'root'

Not being equivalent to this:

# echo '$USER'
$USER
# bash -c $'echo \'$USER\''
$USER

Or to this:

# echo \'\$USER\'
'$USER'
# bash -c $'echo \\\'\\$USER\\\''
'$USER'

But rather to this:

# echo \'$USER\'
'root'
# bash -c $'echo \\\'$USER\\\''
'root'

Possible clarification:

If a command is specified, it is passed to the shell’s -c option as the concatenation of the command and all its arguments separated by spaces, after escaping each character (including spaces) through a slash, except for the alphanumerics, underscores, hyphens and dollar signs.

This is based on:

sudo/src/parse_args.c

Lines 634 to 642 in 7baee70

for (dst = cmnd, av = argv; *av != NULL; av++) {
for (src = *av; *src != '\0'; src++) {
/* quote potential meta characters */
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
*dst++ = '\\';
*dst++ = *src;
}
*dst++ = ' ';
}

It could perhaps be explicitly noted that, at least in the case of bash, the resulting shell command is always a simple command: “A simple shell command such as echo a b c consists of the command itself followed by arguments, separated by spaces. More complex shell commands are composed of simple commands arranged […]”. This touches on three different meanings for ‘command’ (shell command, simple command, command), which may have (also) been the source of confusion for a closely related issue: #78, “-s option command string manipulation”. Using the example from that issue, in sudo -s "whoami; whoami", the whoami; whoami is passed as the command in a simple command, not as a shell command consisting of a list of two simple commands.

millert added a commit that referenced this issue Jan 20, 2022
The concatenation of command and arguments and escaping of special
characters was not documented.
Text adapted from GitHub issue #121 from Kris Rinzwind
@millert
Copy link
Collaborator

millert commented Jan 28, 2022

The changes are present in the 1.9.9 release.

@millert millert closed this as completed Jan 28, 2022
@Rinzwind
Copy link
Author

Thank you!

Something I will note here just for future reference is that ssh behaves differently, see: openssh/openssh-portable#139.

So using ssh:

$ ssh ${destination:?} echo foo ';' echo bar
foo
bar
$ bash -c 'echo foo ; echo bar'
foo
bar
$ echo foo ; echo bar
foo
bar

This is akin to using eval:

$ eval echo foo ';' echo bar
foo
bar

Versus using sudo:

$ sudo --login echo foo ';' echo bar
foo ; echo bar
$ bash -c 'echo foo \; echo bar'
foo ; echo bar
$ echo foo \; echo bar
foo ; echo bar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants