点击(此处)折叠或打开
- if (initgroups(ccf->username, ccf->group) == -1) {
点击(此处)折叠或打开
- This form of group membership persisted until it was changed in 4.2BSD (circa 1983). With 4.2BSD, the concept of supplementary group IDs was introduced. Not only did we belong to the group corresponding to the group ID in our password file entry, but we also could belong to up to 16 additional groups. The file access permission checks were modified so that not only was the effective group ID compared to the file's group ID, but also all the supplementary group IDs were compared to the file's group ID.
也就是说一个用户可以最多同时属于16个其他的组. 查看系统文件/etc/group, 该文件每行有四个字段.
group_name: encrpyted_passwd: group_id: group_member
第四个字段即为其他属于这个组的用户名. 这时候再来看man手册关于initgroups就比较容易理解了.
点击(此处)折叠或打开
- The initgroups() function initializes the group access list by reading the group database /etc/group and using all groups of which user is a member. The additional group group is also added to the list.
但是其作用依旧晦涩难懂. 为此我写了些代码做点实验来理解. 注意initgroups函数只能由root用户或者有CAP_SETGID权限的进程调用.
既然这个函数是关于权限的. 那么首先我以root用户创建一个-rw-rw----权限的普通文件.
点击(此处)折叠或打开
-
# touch testfile
- # chmod 660 testfile
那么该进程是可以访问这个文件的.于是我对/etc/group进行修改. 将我所使用的普通用户名加入到root组的组成员中. 不妨将用户名称为foobar.
点击(此处)折叠或打开
- root:X:0:foobar
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <sys/stat.h>
-
#include <sys/types.h>
-
#include <fcntl.h>
-
#include <grp.h>
-
#include <unistd.h>
-
#include <errno.h>
-
static char buf[BUFSIZ];
-
/* 打印此时进程的各种ID */
-
void show_id()
-
{
-
uid_t uid = getuid();
-
gid_t gid = getgid();
-
uid_t euid = geteuid();
-
gid_t egid = getegid();
-
printf("UID: %d\n", uid);
-
printf("GID: %d\n", gid);
-
printf("EUID: %d\n", euid);
-
printf("EGID: %d\n", egid);
-
}
-
int main(int argc, char *argv[])
-
{
-
-
int fd;
-
int n;
-
int i;
-
if (argc != 2) {
-
fprintf(stderr, "Usage %s filename\n", argv[0]);
-
return -1;
-
}
- show_id();
-
/* euid = 0才能执行initgroups函数调用 */
-
if (geteuid() == 0) {
-
if (initgroups("foobar", getgid()) == -1) {
-
perror("initgroups failed");
-
return -1;
- }
-
/* 由于是set-user-id程序, 还原到进程的真实ID */
-
if (setuid(getuid()) == -1) {
-
perror("setuid failed");
-
return -1;
-
}
-
}
-
show_id();
-
fd = open(argv[1], O_RDONLY);
-
if (fd == -1) {
-
perror("open failed");
-
return -1;
-
}
-
while ( (n = read(fd, buf, BUFSIZ)) > 0) {
-
write(STDIN_FILENO, buf, n);
-
}
-
return 0;
- }
运行结果如下:
点击(此处)折叠或打开
-
UID: 1001
-
GID: 1001
-
EUID: 0
-
EGID: 1001
-
UID: 1001
-
GID: 1001
-
EUID: 1001
-
EGID: 1001
- hello world