getegid系统调用及示例

getegid - 获取当前进程的有效组ID

1. 函数介绍

getegid 是一个 Linux 系统调用,用于获取当前进程的有效组 ID(Effective Group ID)。有效组 ID 决定了进程当前对文件和资源的组级访问权限。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

在 Unix/Linux 系统中,每个进程都有多个相关的用户和组 ID:

  • 真实 ID (Real ID):标识运行该进程的实际用户/组

  • 有效 ID (Effective ID):决定当前权限的用户/组 ID

  • 保存的设置 ID (Saved Set ID):用于权限切换的备份 ID

getegid 专门用于获取有效组 ID,这是进程当前用于权限检查的组标识符。

2. 函数原型

1
2
3
4
5
#include <unistd.h>
#include <sys/types.h>

gid_t getegid(void);

3. 功能

返回当前进程的有效组 ID(Effective Group ID)。这是一个只读操作,不会修改任何系统状态。

4. 参数

  • 无参数

5. 返回值

  • 返回当前进程的有效组 ID(gid_t 类型)

  • 不会失败,总是成功返回

6. 相似函数,或关联函数

  • getgid(): 获取真实组 ID(Real Group ID)

  • geteuid(): 获取有效用户 ID(Effective User ID)

  • getuid(): 获取真实用户 ID(Real User ID)

  • setgid(): 设置组 ID

  • setegid(): 设置有效组 ID

  • setregid(): 同时设置真实和有效组 ID

  • setgroups(): 设置补充组列表

  • getgroups(): 获取补充组列表

  • initgroups(): 初始化用户组访问列表

7. 示例代码

示例1:基本使用 - 获取和显示组ID信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>

void print_group_info(const char *label, gid_t gid) {
struct group *grp;

printf("%s: %d", label, gid);

// 尝试获取组名
grp = getgrgid(gid);
if (grp != NULL) {
printf(" (%s)", grp->gr_name);
}
printf("\n");
}

int main() {
gid_t real_gid, effective_gid;

printf("=== 进程组 ID 信息 ===\n");

// 获取真实组 ID
real_gid = getgid();
print_group_info("真实组 ID", real_gid);

// 获取有效组 ID
effective_gid = getegid();
print_group_info("有效组 ID", effective_gid);

// 获取当前用户名
struct passwd *pwd = getpwuid(getuid());
if (pwd != NULL) {
printf("当前用户: %s\n", pwd->pw_name);
}

// 检查是否为 root 组
if (effective_gid == 0) {
printf("注意: 当前进程具有 root 组权限\n");
}

return 0;
}

示例2:权限检查和组切换演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <errno.h>
#include <string.h>

int main() {
gid_t original_egid, current_egid;
int ret;

printf("=== 组 ID 切换演示 ===\n");

// 保存原始有效组 ID
original_egid = getegid();
printf("原始有效组 ID: %d\n", original_egid);

// 尝试切换到不同的组(需要适当权限)
// 这里使用一些常见的系统组进行演示
gid_t test_groups&#91;] = {1000, 1001, 1002}; // 假设的用户组
int num_groups = sizeof(test_groups) / sizeof(test_groups&#91;0]);

for (int i = 0; i < num_groups; i++) {
printf("\n尝试切换到组 %d:\n", test_groups&#91;i]);

// 尝试设置有效组 ID
ret = setegid(test_groups&#91;i]);
if (ret == -1) {
printf(" 切换失败: %s\n", strerror(errno));
switch (errno) {
case EPERM:
printf(" 原因: 权限不足\n");
break;
case EINVAL:
printf(" 原因: 无效的组 ID\n");
break;
default:
break;
}
} else {
current_egid = getegid();
printf(" 切换成功,当前有效组 ID: %d\n", current_egid);

// 切换回原始组 ID
if (setegid(original_egid) == 0) {
printf(" 已切换回原始组 ID: %d\n", getegid());
}
}
}

printf("\n最终有效组 ID: %d\n", getegid());
return 0;
}

示例3:补充组信息获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>

int main() {
gid_t effective_gid;
gid_t *group_list;
int group_count;
long max_groups;

printf("=== 完整组信息展示 ===\n");

// 获取有效组 ID
effective_gid = getegid();
printf("有效组 ID: %d\n", effective_gid);

// 获取组名
struct group *grp = getgrgid(effective_gid);
if (grp != NULL) {
printf("有效组名: %s\n", grp->gr_name);
}

// 获取补充组列表大小
max_groups = sysconf(_SC_NGROUPS_MAX);
if (max_groups == -1) {
max_groups = 64; // 默认值
}

printf("最大支持组数: %ld\n", max_groups);

// 分配组列表内存
group_list = malloc(max_groups * sizeof(gid_t));
if (group_list == NULL) {
perror("内存分配失败");
return 1;
}

// 获取补充组列表
group_count = getgroups(max_groups, group_list);
if (group_count == -1) {
perror("获取补充组列表失败");
free(group_list);
return 1;
}

printf("补充组数量: %d\n", group_count);

if (group_count > 0) {
printf("补充组列表:\n");
for (int i = 0; i < group_count; i++) {
printf(" 组 %d: %d", i + 1, group_list&#91;i]);

// 获取组名
struct group *sup_grp = getgrgid(group_list&#91;i]);
if (sup_grp != NULL) {
printf(" (%s)", sup_grp->gr_name);
}
printf("\n");
}
}

// 检查有效组 ID 是否在补充组列表中
int found = 0;
for (int i = 0; i < group_count; i++) {
if (group_list&#91;i] == effective_gid) {
found = 1;
break;
}
}

printf("\n有效组 ID %s 在补充组列表中\n",
found ? "存在" : "不存在");

free(group_list);
return 0;
}

示例4:权限相关的实际应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <string.h>

// 检查当前进程是否属于指定组
int is_member_of_group(gid_t target_gid) {
gid_t effective_gid = getegid();

// 首先检查有效组 ID
if (effective_gid == target_gid) {
return 1;
}

// 检查补充组
long max_groups = sysconf(_SC_NGROUPS_MAX);
if (max_groups == -1) max_groups = 64;

gid_t *groups = malloc(max_groups * sizeof(gid_t));
if (groups == NULL) return 0;

int ngroups = getgroups(max_groups, groups);
if (ngroups == -1) {
free(groups);
return 0;
}

for (int i = 0; i < ngroups; i++) {
if (groups&#91;i] == target_gid) {
free(groups);
return 1;
}
}

free(groups);
return 0;
}

// 获取当前用户的主要组信息
void print_user_primary_group() {
uid_t uid = getuid();
struct passwd *pwd = getpwuid(uid);

if (pwd != NULL) {
printf("用户 %s 的主要组: %d", pwd->pw_name, pwd->pw_gid);
struct group *grp = getgrgid(pwd->pw_gid);
if (grp != NULL) {
printf(" (%s)", grp->gr_name);
}
printf("\n");
}
}

int main() {
printf("=== 权限检查应用示例 ===\n");

// 显示基本信息
printf("当前用户 ID: %d\n", getuid());
printf("当前有效组 ID: %d\n", getegid());
print_user_primary_group();

// 检查是否属于 wheel 组(系统管理员组)
struct group *wheel_grp = getgrnam("wheel");
if (wheel_grp != NULL) {
int is_wheel = is_member_of_group(wheel_grp->gr_gid);
printf("是否属于 wheel 组: %s\n", is_wheel ? "是" : "否");
}

// 检查是否属于 sudo 组
struct group *sudo_grp = getgrnam("sudo");
if (sudo_grp != NULL) {
int is_sudo = is_member_of_group(sudo_grp->gr_gid);
printf("是否属于 sudo 组: %s\n", is_sudo ? "是" : "否");
}

// 检查是否具有 root 组权限
int is_root_group = is_member_of_group(0);
printf("是否具有 root 组权限: %s\n", is_root_group ? "是" : "否");

// 根据组权限显示不同信息
if (is_root_group) {
printf("\n提示: 当前进程具有 root 组权限,可以执行特权操作\n");
} else {
printf("\n提示: 当前进程权限受限,某些操作可能需要提升权限\n");
}

return 0;
}

8. 组 ID 类型说明

Unix/Linux 系统中的组 ID 类型:

1
2
3
4
5
6
7
8
9
10
11
12
// 真实组 ID (Real Group ID)
// 标识启动进程的用户的组
gid_t real_gid = getgid();

// 有效组 ID (Effective Group ID)
// 当前用于权限检查的组 ID
gid_t effective_gid = getegid();

// 保存的设置组 ID (Saved Set Group ID)
// 用于权限切换的备份 ID
// 通过 setregid() 或类似函数设置

9. 常见组 ID 值

1
2
3
4
5
6
7
8
9
10
11
// 特殊组 ID
0 // root 组 (超级用户组)
1 // bin 组 (系统二进制文件)
2 // daemon 组 (系统守护进程)
3 // sys 组 (系统文件)
4 // adm 组 (系统日志)
5 // tty 组 (终端设备)
6 // disk 组 (磁盘设备)
10 // wheel 组 (系统管理员,某些发行版)
100+ // 普通用户组

10. 实际应用场景

getegid 在以下场景中非常有用:

场景1:权限检查

1
2
3
4
5
6
7
int check_file_access_permission(const char *filename) {
gid_t effective_gid = getegid();
// 根据有效组 ID 检查文件访问权限
// ...
return 0;
}

场景2:安全审计

1
2
3
4
5
6
7
void audit_process_privileges() {
gid_t egid = getegid();
if (egid == 0) {
syslog(LOG_WARNING, "进程以 root 组权限运行");
}
}

场景3:组权限相关的功能控制

1
2
3
4
int can_perform_admin_task() {
return is_member_of_group(get_admin_group_id());
}

11. 与相关函数的配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <unistd.h>
#include <sys/types.h>

// 完整的 ID 管理示例
void demonstrate_id_management() {
printf("真实用户 ID: %d\n", getuid());
printf("有效用户 ID: %d\n", geteuid());
printf("真实组 ID: %d\n", getgid());
printf("有效组 ID: %d\n", getegid());

// 权限切换示例
// seteuid(), setegid() 用于临时权限切换
// setuid(), setgid() 用于永久权限切换
}

总结

getegid 是一个简单但重要的系统调用,用于获取当前进程的有效组 ID。关键要点:

总是成功: 不会失败,总是返回有效组 ID

权限检查: 有效组 ID 决定当前的组级权限

安全相关: 是权限管理和安全检查的基础

配合使用: 通常与 getgroups() 等函数配合使用

实际应用: 广泛用于权限验证、安全审计等场景

在编写需要进行权限检查的程序时,getegid 是必不可少的工具函数,它为程序提供了当前权限状态的重要信息。

getegid系统调用及示例-CSDN博客

https://www.calcguide.tech/2025/09/09/getegid-syscall-demo/

data-ad-format="auto" data-full-width-responsive="true">