我正在使用sudo
bash 以特定用户身份执行任意命令。
这在一般情况下非常有效:
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
已接受的挑战! :) 当然,除了我的方法之外,可能还有很多其他方法可以解决您的问题。
- 所以我有这个-诡异的-文件(位于/home/radis/)。
包含这个:
#!/bin/bash
id
pwd
- 我想让它在 /bin/ 中可用,并带有符号链接,以匹配您的情况
(以 root 身份)。
ln -s /home/radis/-weird- /bin/-weird-
- 此时,以下命令作品在 bash shell (shell:~#) 中。
(在 root 和用户 radis 中)
-weird-
/home/radis/./-weird-
/bin/./-weird-
bash -c ./-weird-
bash -c -- -weird-
- 这作品
(完整情况,以 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-)。
希望能帮助到你。