我有一个以root用户身份运行的damon入门的进程,现在我想将该进程的特权“降级”到普通用户的特权。这可能吗?如果是,怎么办?
PS:在Mac上运行Unix
我有一个以root用户身份运行的damon入门的进程,现在我想将该进程的特权“降级”到普通用户的特权。这可能吗?如果是,怎么办?
PS:在Mac上运行Unix
Answers:
进程本身必须调用setuid(2)。如果尚未在chroot(8)中运行它,则还应该进行调查。据我所知,root用户无法更改另一个进程的uid。
如果您以root用户身份运行它的原因是绑定端口,则建议以普通用户身份在更高的端口上运行它,并在OS X上使用ipfw(8)将端口80/443 / etc转发到更高的端口:
http://support.crashplanpro.com/doku.php/recipe/forward_port_443_to_pro_server_on_mac_osx
setuid()
单靠电话绝对是不够的。
sudo tcpdump -Z
使用initgroups(3),setgid(2)和setuid(2)删除其自身进程的root特权。
# code taken from:
# http://www.opensource.apple.com/source/tcpdump/tcpdump-32/tcpdump/tcpdump.c
/* Drop root privileges and chroot if necessary */
static void
droproot(const char *username, const char *chroot_dir)
{
...
if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n",
username,
(unsigned long)pw->pw_uid,
(unsigned long)pw->pw_gid,
pcap_strerror(errno));
exit(1);
}
...
}
initgroups
,setgid
,setuid
(最后!)也正是在UNIX上,右范式,并应始终遵循。此外,即使所有三个主要功能均返回成功,负责的“ droproot”功能也会检查其uid和gid是否已正确设置。
您可以使用其他用户身份运行命令su
:
su USERNAME -c COMMAND
将COMMAND
特权降为时运行USER
。
请注意,默认情况下,su
将使用目标用户的外壳解释器来运行命令。相比之下,的默认行为sudo
是将COMMAND
视为独立程序,即在当前环境中运行。当然,可以使用各种开关和环境变量来更改这些默认行为。
su
如果USERNAME没有定义外壳(或/bin/false
),则看起来不起作用,而sudo起作用。
su
将反映出来。但是,始终可以使用-s
开关来覆盖它。请注意,的目的su
是模仿给定用户的行为-通常受其外壳影响。相比之下,sudo
(默认情况下)将忽略目标用户的外壳程序设置。
要放弃特权,您需要非root用户才能进入。然后,只需切换到该用户即可:
#define UNPRIV_UID 48
#define UNPRIV_GID 48
if (getuid() == 0) { // we are root
// setting UID/GID requires root privileges, so if you don't set
// the GID first, you won't be able to do it at all.
if (setgid(UNPRIV_GID)!=0) die("Failed to set nonroot GID");
if (setuid(UNPRIV_UID)!=0) die("Failed to set nonroot UID");
}
ASSERT(getuid() != 0);
请注意,这是在程序本身而不是在包装脚本中完成的。许多程序出于某些特定目的需要root特权(例如,绑定到低号端口),但是此后不需要root。因此,这些程序将以root用户身份启动,但是一旦不再需要它们便放弃特权。
如果您根本不需要root特权,则不要以root用户身份运行它。例如:
# Change this:
myprog -C /my/config/file
# To this:
sudo -u someuser myprog -C /my/config/file
# Or this
su someuser -c "myprog -C /my/config/file"
setuid
功能仅设置有效 UID,而不设置实际UID。setreuid
如果您不希望该过程能够获取特权,则应该使用。(并且上面的代码也不处理补充的组特权。它仅适用于启动最受信任的代码。)
setuid()
确实设置了真实的和保存的用户ID。您可能会想到seteuid()
。并非所有系统都具有setreuid()
,因此不能在所有地方都使用它。的确切语义setuid()
是复杂的,但是如果euid为0,则可以使用删除所有传统的用户ID特权setuid()
。此答案中最大的遗漏之处在于,必须与和一起调用initgroups
或,并且必须在末尾进行更彻底的断言。setgroups
setgid
setuid
如果您正在执行一个不同的可执行文件,即您正在调用函数execve
或exec
函数的另一个家族,可能是间接通过诸如system
或的函数进行popen
,并且子进程从一开始就应该在没有特权的情况下运行,那么最简单的方法是获取一个涉及外壳,并调用su
。以下是代码在Perl中的外观概述,其中显示了所需的引号:
$shell_command = quotemeta($path_to_executable) . " --option";
$shell_command =~ s/'/'\\''/; # protect single quotes for the use as argument to su
$su_command = sprintf("su -c '%s' %s", $shell_command, quotemeta($user_name));
open(PIPE, "$su_command |") or die;
如果子进程需要以root用户身份启动但后来又放弃特权,请参见此答案中的代码,该代码说明了如何在进程中降级特权。