![在 script.sh 中使用 sudo 调用 init.d 中的 init 文件时出现错误 sudo:没有 tty present 并且没有指定 askpass 程序](https://linux22.com/image/1049643/%E5%9C%A8%20script.sh%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20sudo%20%E8%B0%83%E7%94%A8%20init.d%20%E4%B8%AD%E7%9A%84%20init%20%E6%96%87%E4%BB%B6%E6%97%B6%E5%87%BA%E7%8E%B0%E9%94%99%E8%AF%AF%20sudo%EF%BC%9A%E6%B2%A1%E6%9C%89%20tty%20present%20%E5%B9%B6%E4%B8%94%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9A%20askpass%20%E7%A8%8B%E5%BA%8F.png)
我正在尝试编写一个在启动时启动的脚本来连接到我的个人 VPN。
我有一个初始化文件:/etc/init.d/vpnstartup
它在启动时使用以下命令调用我的 vpnon.sh 脚本:
case "$1" in
start)
su username -c $VPN_DIR/vpnon.sh
;;
在我的脚本 vpnon.sh 中有一些需要 root 权限才能执行的命令:
sudo iptables -A INPUT -i pptp -j ACCEPT
sudo iptables -A OUTPUT -o pptp -j ACCEPT
当我使用 ./vpnstartup start 调用我的 init 文件时,我使用 chmod 775 授予 vpnstartup init 文件和 vpnon.sh 脚本的权限
调用 sudo iptables 命令时出现以下错误
sudo: no tty present and no askpass program specified
sudo: no tty present and no askpass program specified
我认为发生的情况是 sudo 命令需要输入密码但无法获取密码。
我发现的唯一解决方案是将其添加NOPASSWD :ALL option
到我的用户名下的 sudoers 文件中。
如果有更好的解决方案,出于安全原因我不想使用此方法。
如果您能帮助我解决这个问题,请告诉我;我在这个问题上花了很多时间。
答案1
我认为这里的关键因素是,由于脚本是用 sudo 运行的,因此它可以执行 root 可以执行的所有操作。问题是该脚本中的其他 sudo 命令不一定继承 root 权限,而是以控制用户的身份执行。这通常会导致您在 sudo 中看到的错误,即使父脚本本身可以通过 sudo 允许,但子命令不允许。
发生的情况是,该脚本中的嵌套 sudo 调用失败,因为 sudo 通常会提示输入密码,但没有控制 shell,所以无法输入。这会产生sudo: no tty present and no askpass program specified
您看到的略显模糊的错误。
一个简单的说明方法是,如果像您的示例一样,init 脚本包含使用 sudo 的内部调用。运行:
sudo /etc/init.d/startvpn
如果您自己的用户没有对所有 sudo 调用的 sudo 权限,则可能会失败,并可能会给您 sudo tty 错误。但是,像这样运行它:
sudo sh /etc/init.d/startvpn
可能会有效。在后一种情况下,sudo sh
以 root 身份创建一个命令 shell,因此在该 shell 中运行的任何东西实际上都是以 root 身份执行的。Root 通常具有不受限制的 sudo 权限,因此命令是否使用 sudo 运行不再重要。
值得一提的是:
- 正如其他人指出的那样,大多数此类混乱情况都可以通过不在脚本中使用 sudo 来避免。通常,使用 sudo 运行时失败的子命令可以在没有 sudo 的情况下正常运行(当父脚本使用 sudo 运行时)。
- 虽然使用运行脚本
sudo sh
可能会解决问题,但这样做同样存在安全隐患。考虑到 sudo 的行为方式是健全性检查,以确保脚本的内容不会执行不该执行的操作,即使脚本本身是允许的。 - 如果您以 sudo 身份运行的用户也拥有足够的综合权限,您可能不会看到任何这些问题。但这些问题可能会在以后出现,例如,如果您使用自己的特权帐户开发脚本,并且在生产中以非特权服务帐户运行它。
- 一般来说,你应该避免向用户账户授予广泛的 sudo 权限来解决此类问题。如果确实需要,请将账户访问规则限制为该用户和该特定命令。
答案2
我找到了解决问题的方法。
我删除了 vpnon.sh 脚本中的所有单独的 sudo 命令,并从脚本外部传入了 sudo。
在我的 /etc/init.d/vpnstartup 文件中,我将其更改su username -c
为sudo $VPN_DIR/vpnon.sh
现在的样子:
case "$1" in
start)
sudo $VPN_DIR/vpnon.sh
;;
然后呼叫sudo update-rc.d vpnstartup defaults
,现在 VPN 在启动时连接!:)