如何在shell脚本中要求root权限?

时间:2015-12-27 03:18:21

标签: linux bash shell unix sh

假设您有一个可能需要root权限的shell脚本。您不希望强制用户将其作为sudo运行。但是,如果它确实需要该权限,您希望提示用户输入其密码,而不是抱怨并强制他们使用ID Age BP Chl DM 1 57 120 5 Y 2 87 134 7.5 N 3 95 111 6 Y 重新输入命令。

您将如何在Bash脚本中执行此操作? sudo似乎有用,但感觉就像是黑客。还有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

这是我经常做的事情。这是松散的伪代码,但应该给你一个想法:

# 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] ...

答案 1 :(得分:2)

命令

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命令是成功还是失败。

答案 2 :(得分:2)

如果您的计划是使用sudo进行权限提升,那么您可能需要处理的一个问题是sudo可以设置为允许root用户访问某些命令而不是其他命令。例如,让我们假设你有一台运行VirtualBox的服务器,管理应用程序的人不同于管理操作系统。您的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,则规范测试是运行命令。运行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

(请注意,这是对系统进程表的查询;我们不希望依赖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 $1"; }
rm_s           () { $PM_SU_CMD "/bin/rm $*"; }

然后在您的脚本中,您只需使用需要以root权限运行的_s版本的东西。

这当然不是解决这个问题的唯一方法。