Python脚本的setuid/setgid包装器

5 投票
1 回答
5716 浏览
提问于 2025-04-18 11:56

我有一个Python脚本,想让它以系统用户guybrush的身份运行,这个用户的UID是200,组名也是guybrush,组ID是200。

目前我的Python脚本(放在/path/to/script.py)是这样的:

#!/usr/bin/env python2
import os

print "uid: %s" % os.getuid()
print "euid: %s" % os.getgid()
print "gid: %s" % os.geteuid()
print "egid: %s" % os.getegid()

我尝试写的C语言包装器(scriptwrap.c)是这样的:

#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {
    setuid(geteuid());
    setgid(getegid());
    return execv("/path/to/script.py", argv);
}

然后我编译、修改文件所有者和权限,步骤如下:

$ gcc scriptwrap.c -o scriptwrap
$ chown guybrush:guybrush scriptwrap
$ chmod 6755 scriptwrap

但是当我运行这个包装器时,得到的输出是:

uid: 1000
euid: 1000
gid: 200
egid: 200

所以不知为什么,只有组ID被设置了(我正常的用户ID是1000)。我该怎么解决这个问题呢?

补充:如果我把脚本的所有者改成root:root并运行它,UID、eUID、GID和eGID都会被设置为0。

另外,我是在Ubuntu 12.04.4 LTS上进行的操作。

1 个回答

6

我搞明白了这个问题(在这个过程中也学到了一些东西)。尴尬的是,我最开始的问题是因为我在Python脚本中打错了字:我把GID打印在了euid的标签下,而把eUID打印在了gid的标签下。哎呀。

所以其实eUID和eGID设置得是正确的——太好了。但是尽管我在C语言的包装中使用了setuidsetgid,UID和GID还是没有设置。

结果发现,这跟setuidsetgid的行为有关,具体取决于你是不是root用户:如果你是root用户,调用setuid会把你的真实UID和有效UID都设置成你传入的值;如果你不是root用户,它只会设置有效UID(来源)。所以我使用setuid(和setgid)实际上是没什么作用的。

不过,可以通过使用setreuidsetregid来设置真实的UID和GID:

#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {
    setreuid(geteuid(), geteuid());
    setregid(getegid(), getegid());
    return execv("/path/to/script.py", argv);
}

这样在运行(修正过的)Python脚本时,会得到以下输出:

uid: 200
euid: 200
gid: 200
egid: 200

撰写回答