Shell/Bash 脚本:正确删除权限

Shell/Bash 脚本:正确删除权限

好吧,首先,我知道这个问题已经被问过几次了,但给出的答案并不完全令我满意。情况是这样的:我写了很多脚本来自动化各种维护任务,目的是完全自动化,一旦启动就不需要交互。现在,各种任务通常需要 root 权限(例如安装东西等),但更多时候我不喜欢使用超级用户权限执行命令或整个块(例如 wget,或提取从网络获取的存档等),以限制最坏情况下的损害。显然,为了满足我的目标,必须使用sudoor调用脚本su,并根据命令删除权限并重新获得权限。

现在我已经考虑了一些选择,但它们并不完全令我满意,因此我想在这里咨询专家,以了解哪一个是最好的解决方案(目的是使代码也易于其他人理解且逻辑结构合理)一旦发布):

1.) 将要以非 root 用户身份执行的位分解到外部文件中,并使用 . 从主脚本中执行该文件su <user> -c /path/to/file。然而,这种方法有一些缺点:首先,它破坏了脚本的逻辑结构,使事情更难以理解和阅读,并且在定义和使用变量时产生问题。

2.) 定义别名或函数来缩短su <user> -c "command"。这是一个非常糟糕的主意,因为 80% 的脚本都具有该特权前缀。除此之外,多行命令也是有问题的(比如包含我不想以 root 身份运行的命令的 if 结构)。

3.) 类似的东西su <user> << EOF << ... EOF可以正确处理整个代码块。如果没有一个让我烦恼的问题:语法高亮,这将是最优雅的解决方案(因为脚本的逻辑结构没有被破坏)。我尝试过的所有主要编辑器都对此处文档内的整个块使用一种颜色。通读 80% 没有语法突出显示的脚本并不好。

没有真正优雅的方法来处理这个问题吗?类似su <user> -c ( ...)不带引号的东西会很酷。或者我应该切换到另一个外壳? (现在我使用bash,我听说zsh有一个功能,允许设置EUID变量或类似的东西?)如果没有优雅的解决方案,哪种方法更好?

答案1

zsh,如果运行为root并且您设置

EUID=1000

它将把 euid 设置为 1000。真正的 uid 仍将设置为 0,因此您可以返回到 EUID 0。您运行的任何程序也可以通过执行 a 来重新获得权限,setuid()但如果目的是防止无意中损害而不是防范恶意软件,那么这就足够了。

#! /bin/zsh -
GID=1000 # optional
EUID=1000 # drop *effective* privileges

some-potentially-harmful-command-that-doesnt-need-superuser

and-another

EUID=0 some-command-that-needs-superuser

more-non-privileged-commands

EUID=0 UID=1000 # now drop privileges with no coming back 
# alternatively:
# USERNAME=stephane # sets uid, gid, supplementary groups... based on the user db

请注意,您可以在命令持续时间内设置 EUID/UID...

UID=1000 the-command

但不是UIDUSERNAME如果the-command是内置的或函数,则zsh不会派生不同的进程,因此无法恢复真实的用户 ID。

您还可以在子 shell 中设置EUID// :UIDUSERNAME

(EUID=0 USERNAME=stephane; untrusted-application)

(我们将 EUID 设置为 0,以便之后能够切换用户)。

答案2

一种解决方案是元编程:将各种非特权代码片段创建为单独的文件,并使用预处理器创建最终文件。这样,程序可以轻松地作为单独的位或作为整体来读取。进程之间的通信必须使用文件来完成,这有点麻烦,但使得将特权信息泄漏到非特权文件的可能性大大降低(因为您必须显式“泄漏”每条信息)。

privileged.sh:

echo "Privileged user: $(whoami)"
su - somebody <<'EOF'
%unprivileged.sh%
EOF

unprivileged.sh:

echo "Unprivileged user: $(whoami)"

preprocessor.sh:

while IFS= read -r line
do
    if [[ $line =~ ^%([^%]*)%$ ]]
    then
        cat "${BASH_REMATCH[1]}"
    else
        printf '%s\n' "$line"
    fi
done < privileged.sh > program.sh

测试运行:

$ bash preprocessor.sh 
$ sudo bash program.sh 
Privileged user: root
Unprivileged user: somebody

答案3

3.) 像 su << EOF << ... EOF 这样的东西可以正确处理整个代码块。如果没有一个让我烦恼的问题:语法高亮,这将是最优雅的解决方案(因为脚本的逻辑结构没有被破坏)。我尝试过的所有主要编辑器都对此处文档内的整个块使用一种颜色。通读 80% 没有语法突出显示的脚本并不好。

您应该能够在中定义自定义语法突出显示维姆让它做你想做的事本文文章可能也令人感兴趣。

相关内容