#include <unistd.h>
uid_t getuid(void); //返回:调用进程的实际用户ID
uid_t geteuid(void); //返回:调用进程的有效用户ID
uid_t getresuid(void); //返回:调用进程的设置用户ID
gid_t getgid(void); //返回:调用进程的实际组ID
gid_t getegid(void); //返回:调用进程的有效组ID
gid_t getresgid(void); //返回:调用进程的有效组ID
//这些函数都没有出错返回
二、更改用户ID和更改组ID(setuid、setgid)
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_ gid);
//返回值:若成功返回0;失败返回-1
- 功能:用来更改用户ID/组ID
- 注意:实际用户ID只能由root权限修改
更改ID的规则如下:
下面我们以更改用户ID为例(关于用户ID我们所说明的一切也适用于组ID):
- ①若进程具有超级用户特权,则setuid函数将实际用户ID、有效用户ID、保存的设置用户ID设置为uid
- ②若进程没有超级用户特权,则uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不更改实际用户ID和保存的设置用户ID
- ③如果上面两个条件都不满足,则errno设置为EPERM,并返回-1
_POSIX_SAVED_IDS常量
- 如果没有定义_POSIX_SAVED_IDS常量,则上面那些设置规则都无效
- 可以在编译时测试该常量,或者在运行时通过sysconf函数来判断是否定义该常量,见文章:javascript:void(0)
实际用户ID、有效用户ID、保存的设置用户ID介绍
下面我们以用户ID为例(关于用户ID我们所说明的一切也适用于组ID):
- 实际用户ID:
- 只有超级用户进程可以更改实际用户ID
- 通常,实际用户ID是在用户登录时,由login程序设置的。而且绝不会改变它。因为login是一个超级用户进程,当它调用setuid时,设置所有3个用户ID
- 有效用户ID:
- 仅当对程序文件设置了设置用户ID位时,exec函数才设置有效用户ID;如果设置用户ID位没有设置,exec函数不会改变有效用户ID,而谁维持其现有值
- 任何时候都可以调用setuid,将有效用户ID设置为实际用户ID或保存的设置用户ID
- 自然地,不能将有效用户ID设置为任意随机值
- 保存的设置用户ID:
- 保存的设置用户ID是由exec复制有效用户ID而得到的
- 如果设置了文件的设置用户ID位,则在exec根据文件的用户ID设置了进程的有效用户ID以后,这个副本就被保存起来了
获取ID值
- 总结:
#include <unistd.h>
int setreuid(uid_t ruid,uid_t euid);
int setregid(gid_t rgid,gid_t egid);
//返回值:若成功,返回0;失败,返回-1
- 功能:用户交换实际用户ID和有效用户ID
- 参数:
- 参数1:实际用户/组ID
- 参数2:有效用户/组ID
- 如果任一一个参数的值为-1,则表示相应的ID应当保持不变
- 这两个函数设计的目的:非特权用户也可以交换实际用户ID和有效用户ID。于是就允许一个设置用户ID的程序交换成用户的普通权限,以后又可再次交换回设置用户ID权限
- POSIX.1引进了保存的设置用户ID特性后,其规则也相应的加强,它允许一个非特权用户将其有效用户ID设置为保存的设置用户ID
#include <unistd.h>
int seteuid(uid_t uid);
int setegid(gid_ gid);
//返回值:若成功返回0;失败返回-1
- POSIX.1包含了这两个函数,它们类似于setuid和setgig,但是这两个函数只更改有效用户ID/有效组ID
- 一个非特权用户可将其有效用户ID设置为其实际用户ID或其保存的设置用户ID,对于一个特权用户则可将有效用户ID设置为uid
- 上面的函数我们都是以用户ID为例,其实上面的方式都适用于组ID,但是附属组ID不受setgid、setregid、setegid