这是一个演示我的问题的程序的完整源代码 (操作系统是Ubuntu 14.04 32位,如果重要的话):
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
int status, fd;
printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid());
fd = open("/dev/ttyS0", O_WRONLY);
if(fd < 0)
{
printf("Error opening /dev/ttyS0: %s\n", strerror(errno));
return 1;
}
printf("Successfully opened /dev/ttyS0\n");
close(fd);
/* DROP PRIVILEGES */
setgid(1000);
setuid(1000);
printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid());
fd = open("/dev/ttyS0", O_WRONLY);
if(fd < 0)
{
printf("Error opening /dev/ttyS0: %s\n", strerror(errno));
return 1;
}
printf("Successfully opened /dev/ttyS0\n");
return 0;
}
系统中有两个用户:root和一个普通的非root用户(让我们称他为“ubuntu”),id = 1000。上面的程序试图打开一个串口(/ dev / ttyS0)两次:第一次作为root或ubuntu(取决于它是如何被调用的),第二次总是作为ubuntu。第一次尝试失败导致程序中止。用户ubuntu是拨出组的成员,因此理论上他有必要的权限来打开/ dev / ttyS0。我以四种不同的方式调用该程序:
1)直接以ubuntu
运行调用:
&lt;我的程序路径&gt;
2)以ubuntu运行,但使用sudo
调用:
sudo -u ubuntu&lt;我的程序路径&gt;
3)以root身份运行,但权限已降至ubuntu的权限 (因此,有效地,以ubuntu运行):
调用:
sudo su在所有三种情况下,我得到以下预期结果:
CURRENT UID: 1000, CURRENT GID: 1000
Successfully opened /dev/ttyS0
CURRENT UID: 1000, CURRENT GID: 1000
Successfully opened /dev/ttyS0
然而,在最后一种情况下,会发生一些奇怪的事情:
4)直接以root身份运行
调用:
sudo su结果:
CURRENT UID: 0, CURRENT GID: 0
Successfully opened /dev/ttyS0
CURRENT UID: 1000, CURRENT GID: 1000
Error opening /dev/ttyS0: Permission denied
当然这是我不理解输出的最后两行:这次,当root删除了他的权限时,事实证明ubuntu没有足够的权限来打开/ dev / ttyS0,但为什么呢?这种情况与案例1-3有什么不同?
最后一件值得一提的事:如果我更改了我的代码行:
setgid(1000);
到此:
setgid(20); /* 20 is the id of dialout group */
然后最后一次尝试打开/ dev / ttyS0也是成功的。
当我以root身份运行程序然后通过将uid和gid更改为1000来删除ubuntu的权限时,是否意味着有关ubuntu成为拨出组成员的信息会丢失?你能否详细解释一下我的例子中的案例4以及为什么结果与我预期的不同?
答案 0 :(得分:2)
设置userid和groupid 不自动设置所有补充组(即所有组,不是用户的主要组,而是/etc/groups
中分配给他的所有组)。尝试使用
initgroups("ubuntu", 1000);
在setgid()
之前调用。然后,该进程应具有拨出 -group的权限。