我知道以普通用户身份运行 root 脚本存在风险,但在这种情况下我别无选择,而且我所做的事情与机器有关。我有一台带有 GPIO 端口的小型板计算机,我需要使用其中一个输出通过切换关机线来重置设备。该部件工作正常,设备按预期重置。
我的问题是我编写了一个 python 脚本来重置设备并且它可以工作,但我必须以 root 或“sudo 程序名称,输入密码”身份运行它。但我需要它作为没有 root 权限的普通用户工作。换句话说,我添加了一个普通用户,无论我做什么都无法运行该脚本。
我尝试将用户添加到 sudoer 文件中,但这不起作用并且被完全忽略。我已经更改了权限,设置了 SUID 位以及我能想到的所有其他内容,但它仍然要求输入 root 密码。唯一有效的是当我打开“用户和组”并将用户添加到 Sudo 组时,但随后该用户有权访问我希望它没有的程序,因为它就像我的默认管理员用户一样。那不是我想要的。我想以某种方式限制该用户可以访问的内容,即单个脚本或程序。
我让其他人建议我需要编写一个驱动程序,但我真的不知道如何做到这一点,也不知道他们到底是什么意思,而且通常他们不想详细说明。尽管我使用过一些 Linux,但我并不认为自己是该领域的专家。有人知道如何做到这一点吗?
答案1
找到了解决方案这里。
您想要做的是用 C 语言编写一个受信任的 I/O 启用程序,仅允许访问所需的端口,然后使用execvp()在调用者的地址空间执行脚本。然后,您可以将uid root 设置为已编译的I/O 启用程序。
以下是改编自上述源代码的一些示例代码(请务必使用您不介意写入的地址块):
#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>
#define DESIRED_PORT 0x300
#define NUM_BYTES 8
int main(int argc, char*argv[])
{
if (argc < 2) {
printf("Error: no target program specified.\n");
exit(1);
}
if (ioperm(DESIRED_PORT, NUM_BYTES, 1)) {
printf("Error: couldn't set port permissions.\n");
exit(1);
}
// Set uid to current user's id before executing the script
setgid(getgid());
setuid(getuid());
if (execvp(argv[1], &argv[1]) < 0) {
printf("Error: target program execution error.\n");
exit(1);
}
}
我们将其命名为 io_enable.c,然后编译并设置 uid root:
$ gcc io_enable.c -o io_enable
$ sudo chown root io_enable
$ sudo chmod u+s io_enable
接下来,我们可以使用以下Python脚本对其进行测试:
#!/usr/bin/python
import portio
ADDR = 0x300
fd = open('/tmp/portio.log', 'w')
for i in range(10):
portio.outb(i, ADDR)
fd.write('Wrote %d, read %d.\n' % (i, portio.inb(ADDR)))
fd.close()
我将其命名为 io_test.py,然后像这样运行它:
$ ./io_enable python io_test.py
看起来它有效:
$ cat /tmp/portio.log
Wrote 0, read 0.
Wrote 1, read 1.
Wrote 2, read 2.
Wrote 3, read 3.
Wrote 4, read 4.
Wrote 5, read 5.
Wrote 6, read 6.
Wrote 7, read 7.
Wrote 8, read 8.
Wrote 9, read 9.
答案2
将此行添加到sudoers
文件中(使用程序visudo
,切勿直接编辑文件sudoers
),其中bob
是必须允许运行脚本的用户名:
bob ALL = (root) NOPASSWD: /path/to/my/script
如果您希望多个用户这样做,请将他们放入一个组中resetters
并制作该sudoers
行
%resetters ALL = (root) NOPASSWD: /path/to/my/script
如果还有其他规则bob
,请注意sudoers
文件中的最后一个匹配项计数。因此,将带规则的规则放在NOPASSWD:
不带规则的规则下方。