sudo 清理用户输入,避免出现错误“bash: 无效选项”或“sh: 无效选项”

sudo 清理用户输入,避免出现错误“bash: 无效选项”或“sh: 无效选项”

我正在使用sudobash 以特定用户身份执行任意命令。

这在一般情况下非常有效:

sudo --login --user=maria -- "$COMMAND"

例如,这/bin/whoami完美地调用命令:

sudo --login --user=maria -- "whoami"
maria

但是,请假装您有一个名为的命令/bin/-something-

相反,这不是工作:

sudo --login --user=maria -- "-do-things-"
-sh: 0: Illegal option -d

这是怎么回事?为什么我的参数被混淆为 shell 选项?

故障排除

我理解这-do-things-像 shell 选项-d(由 sudo 执行的内部 shell)一样令人困惑,因此某些东西可能无法正确清理输入。

根据sudo手册页:

  • sudo 支持--将 sudo 选项与command(所以我已经在使用它了)分开

相关sudo --login手册页部分:

如果指定了命令,则使用 -c 选项将其作为简单命令传递给 shell。命令和任何参数连接在一起,用空格分隔

因此,sudo在内部--login COMMAND运行$SHELL -c 'COMMAND'

因此,在我的环境 (Debian) 中,默认情况下会运行bash -c。因此,我浏览了bash手册页以了解-c。相关部分:

-c 如果存在 -c 选项,则从第一个非选项参数命令字符串中读取命令。

因此,我尝试了各种无意义的尝试,也尝试了双重转义--(一次用于 sudo,一次用于sh),但没有成功,都给出了相同的非法选项错误:

COMMAND="-do-things-"
sudo --login --user=maria -- "$COMMAND"
sudo --login --user=maria -- -- "$COMMAND"
sudo --login --user=maria -- "-- $COMMAND"

/bin/bash: --: invalid option

我也尝试了不同的 shell,例如/bin/sh,但出现了同样的错误:

export SHELL=/bin/sh
COMMAND="-do-something"
sudo --shell --user=maria -- "$COMMAND"
sudo --shell --user=maria -- -- "$COMMAND"
sudo --shell --user=maria -- "-- $COMMAND"

/bin/sh: 0: Illegal option --

补充笔记

到达这一点,前提是我认为 sudo 正在尝试执行此操作(无论 shell 是什么):

bash -c -do-things-
sh   -c -do-things-

并假设这些作品

bash -c -- -do-things-
sh   -c -- -do-things-

我可能发现了一个小的 sudo 错误,因为它可能缺少内部转义--(或使用它的可能性)来将 shell 选项与用户提供的命令分开。

无论如何,我现在无法证明这一点,因为我对 sudo 代码库并不完全熟悉。

https://github.com/sudo-project/sudo

感谢任何故障排除提示,并最终了解如何在这个简单的包装器中正确清理用户输入。

答案1

已接受的挑战! :) 当然,除了我的方法之外,可能还有很多其他方法可以解决您的问题。

  1. 所以我有这个-诡异的-文件(位于/home/radis/)。

包含这个:

#!/bin/bash
id
pwd
  1. 我想让它在 /bin/ 中可用,并带有符号链接,以匹配您的情况

(以 root 身份)。

ln -s /home/radis/-weird- /bin/-weird-
  1. 此时,以下命令作品在 bash shell (shell:~#) 中。

(在 root 和用户 radis 中)

-weird-
/home/radis/./-weird-
/bin/./-weird-
bash -c ./-weird-
bash -c -- -weird-
  1. 作品

(完整情况,以 root 身份)

COMMAND="-weird-" 
COMMAND_SAN=$(echo $COMMAND |sed 's/-/\\-/g')

sudo --login --user=radis bash -c -- "$COMMAND"
sudo --login --user=radis bash -c "$COMMAND_SAN"

#this also works (alternate ways when using relative filepaths)
sudo --login --user=radis bash -c -- "./$COMMAND"
sudo --login --user=radis bash -c "./$COMMAND"

一些解释

关键点 1:为了使 sudo 工作,您不需要将整个命令行括在双引号中(这不是必需的)。

关键点 N°2:在 sudo 命令行开始处使用 '-c' 调用 bash 有助于防止将 '-' 解释为参数。

关键点 3:使用“bash -c”以及字符转义(COMMAND_SAN)可确保破折号始终被视为字符,而不是参数。

关键点 N°4:通过提供完整路径或相对路径来执行脚本时,使用相对路径指示符“./”可以将破折​​号解释为字符而不是文件名中的参数(例如:/home/radis/./-weird-)。

希望能帮助到你。

相关内容