实际用户 ID 和实际组 ID
实际用户 ID 和实际组 ID 确定了进程所属的用户和组。【登录 shell 会从/etc/passwd 文件中读取相应用户密码记录的第三和第四字段,作为其实际用户 ID 和实际组 ID】【创建新进程时,将从其父进程中继承这些 ID】
有效用户 ID 和有效组 ID
当进程尝试执行各种系统调用时,将结合有效用户 ID、有效组 ID 和辅助组 ID 一起确定授予进程的权限。【通常有效用户 ID 及组 ID 与其相应的实际 ID 相等】
Set-User-ID 和 Set-Group-ID 程序
set-user-ID 程序会将进程的有效用户 ID 置为可执行文件的用户 ID(属主),从而获得常规情况下并不具有的权限。set-group-ID 程序对进程有效组 ID 实现类似任务。【非特权用户能够对其拥有的文件进行设置,而特权用户能够对任何文件进行设置】
当使用 ls -l
命令查看文件权限时,如果为程序设置了 set-user-ID 权限位和 set-group-ID 权限位,那么通常用来表示文件可执行权限的 x 标识会被 s 标识所替换。
1
2
3
4
5
6
7
8
9
|
$ su
Password:
# ls -l prog
-rwxr-xr-x 1 root root 302585 Jun 26 15:05 prog
# chmod u+s prog // turn on set-user-ID permission bit
# chmod u+s prog // turn on set-group-ID permission bit
# ls -l prog
-rwsr-sr-x 1 root root 302585 Jun 26 15:05 prog
|
当允许 set-user-ID 程序【通过调用 exec()将 set-user-ID 程序加入进程的内存中】时,内核会将进程的有效用户 ID 设置为可执行文件的用户 ID。set-group-ID 行为类似。【换言之,执行该程序的用户,获得了常规情况下所不具有的权限】
保存 set-user-ID 和 保存 set-group-ID
- 若可执行文件的 set-user-ID(set-group-ID)权限位已开启,则将进程的有效用户(组)ID 置为可执行未见得属主。若未设置 set-user-ID(set-group-ID)权限位,则进程的有效用户(组)ID 将保持不变。
- saved set-user-ID 和 saved set-group-ID 的值由对应的有效 ID 复制而来。
文件系统用户 ID 和组 ID
文件系统用户 ID 和组 ID 决定了打开文件、改变文件属主、修改文件权限之类文件系统操作的操作权限。【通常文件系统用户 ID 和组 ID 的值等同于相应的有效用户 ID 和组 ID】
辅助组 ID
辅助组 ID 用于标识进程所属的若干附加的组
获取和修改进程凭证
获取和修改实际、有效和保存设置标识
1
2
3
4
5
6
7
8
9
|
#include <unistd.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
int setuid(uid_t uid);
int setgid(gid_t git);
|
系统调用 getuid() 和 getgid() 分别返回调用进程的实际用户 ID 和组 ID。系统调用 geteuid() 和 getegid() 则对进程的有效 ID 实现类似功能。
setuid() 系统调用以给定的 uid 参数值来修改调用进程的有效用户 ID,也可能修改实际用户 ID 和保存 set-user-ID。系统调用 setgid()则对相应组 ID 实现了类似功能。
- 当非特权进程调用 setuid 时,仅能修改进程的有效用户 ID。
- 当特权进程以一个非 0 参数调用 setuid()时,其实际用户 ID、有效用户 ID 和保存 set-user-ID 均被置为 uid 参数所指定的值。
进程能够使用 seteuid() 和 setegid() 来修改其有效用户/组 ID。
1
2
3
4
|
#include <unistd.h>
int seteuid(uid_t uid);
int setegid(gid_t gid);
|
- 非特权进程仅能使其有效 ID 修改为相应的实际 ID 或保存设置 ID
- 特权级进程能够将其有效 ID 修改为任意值
setreuid() 和 setregid() 系统调用允许调用进程独立修改及实际和有效用户/组 ID
1
2
3
4
|
#include <unistd.h>
int setreuid(uid_t ruid, uid_t euid);
int setergid(gid_t rgid, gid_t egid);
|
- 非特权进程只能将其实际用户 ID 设置为当前实际用户 ID 或有效用户 ID,且只能将有效用户 ID 设置为当前实际用户 ID、有效用户 ID 或保存 set-user-ID
- 特权级进程能够设置其实际用户 ID 和有效用户 ID 位人一直
1
2
3
4
5
6
7
|
#define _GNU_SOURCE
#include <unistd.h>
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
int setresuid(uid_t ruid, uid_t euid, uid_t suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
|
getresuid() 和 getresgid() 系统调用将调用进程的当前实际用户/组 ID、有效用户/组 ID 和保存 set-user-ID/set-group-ID 值返回至给定的三个参数所指定的位置。
setresuid() 和 getresgid() 系统调用允许调用进程独立修改器三个用户/组 ID 的值。
获取和修改文件系统 ID
1
2
3
4
|
#include <sys/fsuid.h>
int setfsuid(uid_t fsuid);
int setfsgid(gid_t fsgid);
|
setfsuid() 和 setfsgid() 系统调用将进程文件系统用户/组 ID 修改为参数所指定的值。
获取和修改辅助组 ID
1
2
3
|
#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);
|
getgroups 仅返回调用进程的辅助组 ID
若进程属组的数量常熟 gidsetsize,则 getgroups 将返回错误【EINVAL】。可将 grouplist 数组的大小调整为常量 NGROUPS_MAX+1 以避免这种情况。
1
2
3
4
5
|
#define _BSD_SOURCE
#include <grp.h>
int setgroups(size_t gidsetsize, const gid_t *grouplist);
int initgroups(const char* user, gid_t group);
|
setgroups 系统调用使用 grouplist 数组所指定的集合来替换调用进程的辅助组 ID。
initgroups 函数将扫描 /etc/groups
文件,为 user 创建属组列表,一次初始化调用进程的辅助组 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/fsuid.h>
#include <limits.h>
#include "ugid_functions.h" /* username_from_id() & group_name_from_id() */
#include "tlpi_hdr.h"
#define SG_SIZE (NGROUPS_MAX + 1)
int main(int argc, char *argv[])
{
uid_t ruid, euid, suid, fsuid;
gid_t rgid, egid, sgid, fsgid;
gid_t suppGroups[SG_SIZE];
int numGroups, j;
char *p;
if (getresuid(&ruid, &euid, &suid) == -1)
errExit("getresuid");
if (getresgid(&rgid, &egid, &sgid) == -1)
errExit("getresgid");
/* Attempts to change the file-system IDs are always ignored
for unprivileged processes, but even so, the following
calls return the current file-system IDs */
fsuid = setfsuid(0);
fsgid = setfsgid(0);
printf("UID: ");
p = username_from_id(ruid);
printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long)ruid);
p = username_from_id(euid);
printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long)euid);
p = username_from_id(suid);
printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long)suid);
p = username_from_id(fsuid);
printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long)fsuid);
printf("\n");
printf("GID: ");
p = group_name_from_id(rgid);
printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long)rgid);
p = group_name_from_id(egid);
printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long)egid);
p = group_name_from_id(sgid);
printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long)sgid);
p = group_name_from_id(fsgid);
printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long)fsgid);
printf("\n");
numGroups = getgroups(SG_SIZE, suppGroups);
if (numGroups == -1)
errExit("getgroups");
printf("Supplementary groups (%d): ", numGroups);
for (j = 0; j < numGroups; j++)
{
p = group_name_from_id(suppGroups[j]);
printf("%s (%ld) ", (p == NULL) ? "???" : p, (long)suppGroups[j]);
}
printf("\n");
exit(EXIT_SUCCESS);
}
|