删除root权限
我有一个以root身份启动的守护程序(因此它可以绑定到低端口)。初始化后,我非常想让它为了安全起见而放弃root权限。删除root权限
任何人都可以指向我在已知的正确的在C代码片段会做到这一点?
我已经阅读过手册页,我已经在不同的应用程序中看到了这个不同的实现,它们都是不同的,有些非常复杂。这是与安全相关的代码,我真的不希望重蹈其他人的同样错误的重犯。我正在寻找的是一种最佳实践,即已知的,可移植的便携式库函数,我可以使用这些函数以获得正确的知识。这样的事情存在吗?
仅供参考:我以root身份启动;我需要改变在不同的用户和gid下运行;我需要让补充小组正确设置;之后我不需要改回根权限。
你要找的这篇文章:
POS36-C. Observe correct revocation order while relinquishing privileges
不知道如何以最佳方式把一些信息,有没有复制该页面的内容...
(非常迟到)正是我在找的东西!谢谢! – 2015-08-08 20:37:55
为了删除所有权限(用户和组),您需要在用户之前删除组。
if (getuid() == 0) {
/* process is running as root, drop privileges */
if (setgid(groupid) != 0)
fatal("setgid: Unable to drop group privileges: %s", strerror(errno));
if (setuid(userid) != 0)
fatal("setuid: Unable to drop user privileges: %S", strerror(errno));
}
如果你是偏执狂:鉴于userid
和groupid
包含用户和要删除该组的ID,并假设有效ID是也根,这是通过调用setuid()和setgid()完成,你可以尝试恢复你的root权限,这应该会失败。如果没有失败,你救助:
if (setuid(0) != -1)
fatal("ERROR: Managed to regain root privileges?");
另外,如果你还是偏执,你可能要seteuid()和setegid()太多,但它不应该是必要的,因为的setuid()和setgid()已经设置了所有ID,如果该进程属于root。
补充组列表是一个问题,因为没有POSIX函数来设置补充组(有getgroups(),但没有setgroups())。有一个BSD和Linux扩展setgroups(),你可以使用,它涉及到你。
您还应该chdir("/")
或任何其他目录,以便进程不会保留在根目录中。
由于你的问题是关于Unix的一般情况,这是非常普遍的方法。请注意,在Linux中,这不再是首选方法。在当前的Linux版本中,您应该将CAP_NET_BIND_SERVICE
capability设置为可执行文件,并以普通用户身份运行它。不需要root权限。
你也想设置gid - 这可能会因unix的不同而有所不同,因为setuid/setgid实际上与真实和已保存的id不一致 – nos 2010-07-28 22:06:45
这确实需要一个可移植的解决方案,所以没有Linux能力fu允许,恐怕。我已经尝试了setuid()和setgid()的简单方法;它不会正确设置组(如果您不调用setgroups(),显然您最终可能仍然是某些根组的成员!)。 – 2010-07-28 22:14:54
@nos谢谢。扩大到覆盖群体。如果进程由root拥有(如OP所述),或者它是setuid-root,则setuid()和setgid()已经设置了所有ID(真实,有效和保存)。这是在说明书中。否则,实现将不符合POSIX。 – Juliano 2010-07-28 22:59:59
这是我能做些什么最好:
#define _GNU_SOURCE // for secure_getenv()
int drop_root_privileges(void) { // returns 0 on success and -1 on failure
gid_t gid;
uid_t uid;
// no need to "drop" the privileges that you don't have in the first place!
if (getuid() != 0) {
return 0;
}
// when your program is invoked with sudo, getuid() will return 0 and you
// won't be able to drop your privileges
if ((uid = getuid()) == 0) {
const char *sudo_uid = secure_getenv("SUDO_UID");
if (sudo_uid == NULL) {
printf("environment variable `SUDO_UID` not found\n");
return -1;
}
errno = 0;
uid = (uid_t) strtoll(sudo_uid, NULL, 10);
if (errno != 0) {
perror("under-/over-flow in converting `SUDO_UID` to integer");
return -1;
}
}
// again, in case your program is invoked using sudo
if ((gid = getgid()) == 0) {
const char *sudo_gid = secure_getenv("SUDO_GID");
if (sudo_gid == NULL) {
printf("environment variable `SUDO_GID` not found\n");
return -1;
}
errno = 0;
gid = (gid_t) strtoll(sudo_gid, NULL, 10);
if (errno != 0) {
perror("under-/over-flow in converting `SUDO_GID` to integer");
return -1;
}
}
if (setgid(gid) != 0) {
perror("setgid");
return -1;
}
if (setuid(uid) != 0) {
perror("setgid");
return -1;
}
// change your directory to somewhere else, just in case if you are in a
// root-owned one (e.g. /root)
if (chdir("/") != 0) {
perror("chdir");
return -1;
}
// check if we successfully dropped the root privileges
if (setuid(0) == 0 || seteuid(0) == 0) {
printf("could not drop root privileges!\n");
return -1;
}
return 0;
}
这在unixes之间有很大的不同 - 有没有特别的?如果你需要一个“便携式”解决方案,它会很麻烦,你最好抓住例如来自OpenSSH的permanent_set_uid()函数 - 在uidswap中。c文件 – nos 2010-07-28 22:05:34