如何在 shell 脚本中要求 root 权限?
How to demand root privileges in a shell script?
假设您有一个可能需要 root 权限的 shell 脚本。您不想强迫用户 运行 它作为 sudo。但是,如果它确实需要该权限,您希望提示用户输入他们的密码,而不是抱怨并强迫他们使用 sudo
.
重新输入命令
您将如何在 Bash 脚本中执行此操作? sudo true
似乎有效,但感觉像是 hack。有没有更好的方法?
命令
sudo -nv
检查用户是否拥有当前 sudo
凭据 (-v
),但如果访问权限已过期 (-n
),将失败而不是提示。
所以这个:
if sudo -nv 2>/dev/null && sudo -v ; then
sudo whoami
else
echo No access
fi
将检查用户的 sudo 凭据是否是最新的,仅当不是时才提示输入密码。
可能存在竞争条件:用户的凭据可能在检查后立即过期。
正如 ghoti 在评论中指出的那样,如果 sudoers
文件设置为仅允许执行某些命令,这可能不起作用。出于这个和其他原因,请务必检查每个 sudo
命令是成功还是失败。
这是我经常做的事情。这是松散的伪代码,但应该给你思路:
# myscript -- possibly execute as sudo
if (passed -e option) then
read variables from envfile
else
...
need_root = ...
# set variables ...
if ($need_root && $uid != 0) then
env [or whatever] > /tmp/envfile
exec sudo myscript -e/tmp/envfile ...
fi
fi
# stuff to execute as root [or not] ...
如果您计划使用 sudo
进行权限升级,您可能需要处理的一个问题是可以将 sudo 设置为允许 root 访问某些命令而不是其他命令。例如,假设您有一台 运行 VirtualBox 服务器,管理应用程序的人员与管理 OS 的人员不同。您的 sudoers
文件可能包含如下内容:
Cmnd_Alias SAFE = /bin/true, /bin/false, /usr/bin/id, /usr/bin/who*
Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/halt, /sbin/reboot
Cmnd_Alias SU = /bin/su, /usr/bin/vi*, /usr/sbin/visudo
Cmnd_Alias SHELLS = /bin/sh, /bin/bash, /bin/csh, /bin/tcsh
Cmnd_Alias VBOX = /usr/bin/VBoxManage
%wheel ALL=(ALL) ALL, !SU, !SHELLS, !SHUTDOWN
%staff ALL=(ALL) !SU, !SHELLS, NOPASSWD: SAFE
%operator ALL=(ALL) SAFE, SHUTDOWN
%vboxusers ALL=(ALL) NOPASSWD: VBOX
在这种情况下,vboxusers
unix 组的成员将始终获得对 sudo -nv
的成功响应,因为该组存在 NOPASSWD 条目。但是该组的成员 运行 使用 VBoxManage 以外的任何其他命令都会收到密码挑战和安全警告。
所以你需要确定你需要运行的命令是否可以运行没有密码提示。如果您不知道 sudo 在您的脚本 运行ning 所在的系统上是如何配置的,规范测试是 运行 命令。 运行 sudo -nv
只会告诉你是否通过认证;它不会告诉您可以访问哪些命令。
就是说,如果您可以安全地依赖 sudo 配置,例如 wheel
组中的成员身份,您就可以访问所有命令,例如:
%wheel ALL=(ALL) ALL
然后您可以使用 sudo -nv
来测试升级能力。但是您的脚本可能有一些东西是 运行 作为 root 的,而有些东西不是。除了 sudo
之外,您可能还想考虑使用其他工具来提升权限。
一个策略可能是在需要时设置一个变量作为命令的前导,但如果您已经是 root 用户(即 运行将整个脚本置于 sudo 中),则将变量留空。
if ! which sudo >/dev/null 2>/dev/null; then
PM_SU_CMD="su - root -c"
elif sudo -nv 2>/dev/null; then
PM_SU_CMD="sudo"
else
echo "ERROR: I can't get root." >&2
exit 1
fi
当然,如果我们已经是 root,请取消设置以避免潜在的冲突:
[ `ps -o uid= $$` -eq 0 ] && unset PM_SU_CMD
(注意这是对系统进程table的查询;我们不想依赖shell的环境,因为那可以被欺骗.)
然后,某些系统实用程序可能会使用以下函数更容易获得:
# Superuser versions for commands that need root privileges
find_s () { $PM_SU_CMD "/usr/bin/find $*"; }
mkdir_s () { $PM_SU_CMD "/bin/mkdir -p "; }
rm_s () { $PM_SU_CMD "/bin/rm $*"; }
然后在您的脚本中,您只需使用 _s
版本的东西,这些东西需要 运行 具有 root 权限。
这当然不是解决这个问题的唯一方法。
假设您有一个可能需要 root 权限的 shell 脚本。您不想强迫用户 运行 它作为 sudo。但是,如果它确实需要该权限,您希望提示用户输入他们的密码,而不是抱怨并强迫他们使用 sudo
.
您将如何在 Bash 脚本中执行此操作? sudo true
似乎有效,但感觉像是 hack。有没有更好的方法?
命令
sudo -nv
检查用户是否拥有当前 sudo
凭据 (-v
),但如果访问权限已过期 (-n
),将失败而不是提示。
所以这个:
if sudo -nv 2>/dev/null && sudo -v ; then
sudo whoami
else
echo No access
fi
将检查用户的 sudo 凭据是否是最新的,仅当不是时才提示输入密码。
可能存在竞争条件:用户的凭据可能在检查后立即过期。
正如 ghoti 在评论中指出的那样,如果 sudoers
文件设置为仅允许执行某些命令,这可能不起作用。出于这个和其他原因,请务必检查每个 sudo
命令是成功还是失败。
这是我经常做的事情。这是松散的伪代码,但应该给你思路:
# myscript -- possibly execute as sudo
if (passed -e option) then
read variables from envfile
else
...
need_root = ...
# set variables ...
if ($need_root && $uid != 0) then
env [or whatever] > /tmp/envfile
exec sudo myscript -e/tmp/envfile ...
fi
fi
# stuff to execute as root [or not] ...
如果您计划使用 sudo
进行权限升级,您可能需要处理的一个问题是可以将 sudo 设置为允许 root 访问某些命令而不是其他命令。例如,假设您有一台 运行 VirtualBox 服务器,管理应用程序的人员与管理 OS 的人员不同。您的 sudoers
文件可能包含如下内容:
Cmnd_Alias SAFE = /bin/true, /bin/false, /usr/bin/id, /usr/bin/who*
Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/halt, /sbin/reboot
Cmnd_Alias SU = /bin/su, /usr/bin/vi*, /usr/sbin/visudo
Cmnd_Alias SHELLS = /bin/sh, /bin/bash, /bin/csh, /bin/tcsh
Cmnd_Alias VBOX = /usr/bin/VBoxManage
%wheel ALL=(ALL) ALL, !SU, !SHELLS, !SHUTDOWN
%staff ALL=(ALL) !SU, !SHELLS, NOPASSWD: SAFE
%operator ALL=(ALL) SAFE, SHUTDOWN
%vboxusers ALL=(ALL) NOPASSWD: VBOX
在这种情况下,vboxusers
unix 组的成员将始终获得对 sudo -nv
的成功响应,因为该组存在 NOPASSWD 条目。但是该组的成员 运行 使用 VBoxManage 以外的任何其他命令都会收到密码挑战和安全警告。
所以你需要确定你需要运行的命令是否可以运行没有密码提示。如果您不知道 sudo 在您的脚本 运行ning 所在的系统上是如何配置的,规范测试是 运行 命令。 运行 sudo -nv
只会告诉你是否通过认证;它不会告诉您可以访问哪些命令。
就是说,如果您可以安全地依赖 sudo 配置,例如 wheel
组中的成员身份,您就可以访问所有命令,例如:
%wheel ALL=(ALL) ALL
然后您可以使用 sudo -nv
来测试升级能力。但是您的脚本可能有一些东西是 运行 作为 root 的,而有些东西不是。除了 sudo
之外,您可能还想考虑使用其他工具来提升权限。
一个策略可能是在需要时设置一个变量作为命令的前导,但如果您已经是 root 用户(即 运行将整个脚本置于 sudo 中),则将变量留空。
if ! which sudo >/dev/null 2>/dev/null; then
PM_SU_CMD="su - root -c"
elif sudo -nv 2>/dev/null; then
PM_SU_CMD="sudo"
else
echo "ERROR: I can't get root." >&2
exit 1
fi
当然,如果我们已经是 root,请取消设置以避免潜在的冲突:
[ `ps -o uid= $$` -eq 0 ] && unset PM_SU_CMD
(注意这是对系统进程table的查询;我们不想依赖shell的环境,因为那可以被欺骗.)
然后,某些系统实用程序可能会使用以下函数更容易获得:
# Superuser versions for commands that need root privileges
find_s () { $PM_SU_CMD "/usr/bin/find $*"; }
mkdir_s () { $PM_SU_CMD "/bin/mkdir -p "; }
rm_s () { $PM_SU_CMD "/bin/rm $*"; }
然后在您的脚本中,您只需使用 _s
版本的东西,这些东西需要 运行 具有 root 权限。
这当然不是解决这个问题的唯一方法。