在脚本中请求root特权


23

我有一个可以sudo script.sh或运行的脚本pkexec script.sh

如果从名称的角度运行脚本,如果脚本要求用户输入密码,从用户的角度来看会更好script.sh

如何以root权限“嵌入”请求pkexecsudo运行整个脚本?

请注意,使用sudo sh -c脚本运行所有功能可能不是最佳解决方案,因为我在脚本中具有函数。

Answers:


55

这将起作用:

echo "$(whoami)"

[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

例:

./test.sh 
blade
[sudo] password for blade: 
root

3
这样做的好处是递归exec-本身可以调用,但同时可以替换进程,因此我们不会生成脚本的多个实例
Sergiy Kolodyazhnyy

1
递归救援!!!提醒我在几天之内为这笔赏金添加赏金!
Fabby

6
执行此操作时需要注意的一点是特权升级。基本上,您以root身份运行的命令越多,恶意黑客利用该漏洞利用某些东西来访问root帐户的机会就越大。我并不是说让整个脚本都以root身份运行总是错误的,但是在您决定这样做之前值得考虑一下。我认为如果答案能够解决问题,那将是很好的(尽管不是必需的)。
David Z

如果在/ etc / sudoers中设置了适当的超时值,则可以选择将sudo放在脚本中确实需要root访问权限的每个命令的前面,并且只会询问一次。我经常搞砸的一件事是,从gui调用这样的脚本是行不通的,因为sudo获取/ dev / null进行密码输入会失败。这就是gksudo和kdesudo旨在处理的内容,因为它们将使用gui询问密码。

1
@ Coder256:我认为您的编辑不正确。 "$@"将扩展为多个单词,每个参数一个。
jwodder

12

如果您想要一个漂亮的对话框,请尝试这样的操作。我从我写的其他东西中直接删除了它,因此它具有您可能不需要或想要的额外内容,但它显示了总体思路:

brand="My Software"

# Check that the script is running as root. If not, then prompt for the sudo
# password and re-execute this script with sudo.
if [ "$(id -nu)" != "root" ]; then
    sudo -k
    pass=$(whiptail --backtitle "$brand Installer" --title "Authentication required" --passwordbox "Installing $brand requires administrative privilege. Please authenticate to begin the installation.\n\n[sudo] Password for user $USER:" 12 50 3>&2 2>&1 1>&3-)
    exec sudo -S -p '' "$0" "$@" <<< "$pass"
    exit 1
fi

sudo对话框

这使用了鞭尾,如果尚未安装,可以安装:

sudo apt-get install whiptail

1
为什么将密码保存在变量中?
heemayl

10
不要打电话exec echo [PASSWORD]它将在命令行上使用任何用户都可以看到的密码生成一个进程。使用内置命令echo(使用强制内置版本builtin echo)或使用bashism <<<(例如:)sudo ... <<< "$pass";Sh和其他外壳这些情况下具有此处的文档。另外,如果密码包含特殊字符,请引用密码。
David Foerster

或者,将whiptail命令放入单独的脚本中,并使用类似的方法SUDO_ASKPASS=/path/to/askpass-with-whiptail.sh sudo -A -p "My password prompt" -- "$0" "$@"sudo处理自定义密码提示。
David Foerster

@DavidFoerster可行,但是您要么需要两个脚本,要么将AskPass脚本写入一个临时文件,然后将其传递给sudo。
迈克尔·汉普顿

好的,但是其他人已经指出,不希望将密码传递给变量。id的方式是将对话框的输出传递到命名管道,如我在此处所示的askubuntu.com/a/704643/295286
Sergiy Kolodyazhnyy

11

blade19899的答案的确是要走的路,但是也可以打电话sudo bash给shebang:

#!/usr/bin/sudo bash
# ...

显而易见的警告是,只有在用脚本调用时./script,此方法才起作用,而在用调用脚本时,该方法将失败bash script


5
这是为什么您永远不要bash script在命令行上键入来调用脚本的原因之一。如果脚本指定bash了该#!行以外的任何其他内容,则使用进行调用bash script将失败。如果我尝试使用bash script.py它调用python脚本,也会失败。
卡巴斯德(Kasperd)'16

1
您可以使用运行它perl script。为了使Perl真正好起来,它检查了shebang行,如果不调用perl,它将运行正确的程序。
tbodt

这很糟糕,因为它使用sudo运行脚本中的每个命令。最好隔离一些真正需要sudo的命令,并在必要时添加它们。在这些sudo调用中不要包括函数的评估;它们应该尽可能清晰和最小。
道格拉斯

@DouglasHeld尽管我可能同意,但这是问题的所在:“我如何“嵌入”对pkexec或sudo的请求,以root权限运行整个脚本?”。可以肯定的是,在某些情况下能够做到这一点将很有用。
kos

6

我在脚本中需要使用root权限的命令开头sudo-如果用户尚未获得许可,则脚本会在此时提示输入密码。

#!/bin/sh 
mem=$(free  | awk '/Mem:/ {print $4}')
swap=$(free | awk '/Swap:/ {print $3}')

if [ $mem -lt $swap ]; then
    echo "ERROR: not enough RAM to write swap back, nothing done" >&2
    exit 1
fi

sudo swapoff -a && 
sudo swapon -a

该脚本可以以sudo <scriptname>或身份运行<scriptname>。无论哪种情况,它只会询问一次密码。


2
这里的问题是,可能有多个命令需要root访问权限,这意味着sudo冗余调用25个不同的命令-一次调用sudo更容易。但是,在这里,您的脚本仅调用sudo一次的原因是因为sudo的时间不超过15分钟-花费比该时间更长的命令将需要重新提示。你的方法行得通。。。不是我需要它工作的方式。
Sergiy Kolodyazhnyy

@Serg对于一个小脚本,我的操作方式既快捷又简单-我确实不是一个优雅的程序员!
查尔斯·格林

您是此页面上最好的程序员。sudo的使用方式与应使用的方式完全相同-仅在需要的地方使用,并且预期效果非常明显。
道格拉斯

4

似乎没有人在这里解决明显的问题。将sudo您的脚本放到您随后分发的目录中会增加不良的用户习惯。(我假设您正在分发它,因为您提到“从用户的角度”。)

事实是,有在使用应用程序和脚本是在银行类似的安全原则的指导方针:永远不要把你的个人信息的人谁打电话给你,说他们是“从您的银行”打电话,并存在由于类似的原因。

申请规则是:

除非出现确定的操作,否则切勿在出现提示时输入密码。 这一律适用于有权sudo访问的任何人。

如果您是因为sudo在命令行上运行而输入密码,那太好了。如果您是因为运行SSH命令而输入的,则可以。当然,如果您是在登录计算机时输入的,那就太好了。

如果您仅运行外部脚本或可执行文件,并在提示输入密码时温和地输入密码,则您不知道该脚本在做什么。众所周知,它可能以纯文本格式存储在临时文件中,甚至可能无法自动清除。

显然,关于运行一组未知命令还有很多其他的问题root,但是我在这里谈论的是维护密码本身的安全性。即使假设该应用程序/脚本不是恶意的,您仍然希望安全地处理您的密码,以防止其他应用程序获取并恶意使用它。

因此,我个人对此的回应是,如果脚本需要root特权,最好将其放入:

#!/bin/bash
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

# do privileged stuff, etc.

尽管我完全同意您的观点sudo script_name,但是在不了解某项功能的情况下运行某项内容的用户同样容易受到攻击,但这是相同的。也许这个主意确实养成了不良习惯-我对此不予赘述。但是关键是要知道程序的作用,这是用户的责任。这就是开源软件背后的全部想法。至于我自己的剧本,很好。。。脚本是纯文本-用户可以读取它,如果他们想知道那是什么
谢尔盖Kolodyazhnyy

@SergiyKolodyazhnyy相似,但是如果直接在脚本中输入密码,那实际上会更糟。使用sudo运行的脚本仍然不知道您的密码。
通配符

1

我这样做是这样的:

echo -n "Enter password for sudo rights: "
read -s pass

echo $pass | sudo -S [your command here]

4
至少引用您的变量。
muru

如果密码以连字符开头,则引用变量甚至可能无济于事
通配符
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.