1. 更改用户ID和组ID
1.1. 设置用户ID和设置组ID
与进程相关联的ID有6个或更多,如下:
实际用户ID |
我们实际上是谁 |
实际组ID |
|
有效用户ID |
用于文件访问权限检查 |
有效组ID |
|
附加组ID |
|
保存的设置用户ID |
由exec函数保存 |
保存的设置组ID |
实际用户ID和实际组ID标识我们是谁。这两个字段在登录时取自口令文件中的登录项。
有效用户ID、有效组ID和附加组ID决定了我们的文件访问权限。
保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。
当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID就是实际组ID。但是如果在文件模式字(st_mode)中设置一个特殊标志,其含义是"当执行此文件时,将进程的有效用户ID设置为文件所有者的用户ID(se_uid)"。与此类似,如果在文件模式字(st_mode)中设置另一位,它使得将执行此文件的进程的有效组ID设置为文件组所有者ID(se_gid)。在文件模式字中的这两位被称为设置用户ID位(set-user-ID)和设置用户组位(set-group-ID)。
1.2. 文件访问权限
st_mode值也包含了针对文件的访问权限位。9个权限位,取自<sys/stat.h>
st_mode屏蔽字 |
意义 |
S_IRUSR |
用户-读 |
S_IWUSR |
用户-写 |
S_IXUSR |
用户-执行 |
S_IRGRP |
组-读 |
S_IWGRP |
组-写 |
S_IXGRP |
组-执行 |
S_IROTH |
其他-读 |
S_IWOTH |
其他-写 |
S_IXOTH |
其他-执行 |
命令chmod用于修改这9个权限位。该命令允许用u表示用户(所有者),用g表示组,用o表示其他。进程每次打开、创建或删除一个文件时,内核就进行文件访问权限测试,而这种涉及文件的所有者(st_ui和st_gid)、进程的有效ID(有效用户ID和有效组ID)以及进程的附加组ID(若支持的话)。两个所有者ID是文件的性质,而两个有效ID和附加组ID是进程的性质。内核顺序进行的测试是:
1). 如果进程的有效用户ID是0(超级用户),则允许访问。
2). 如果进程的有效用户ID等于文件的所有者ID(也就是该进程拥有此文件),那么:若所有者适当的访问权限位被设置,则允许访问。
3). 如果进程的有效组ID或进程的附加组ID之一等于文件的组ID,那么:若组适当的权限位被设置,则允许访问。
4). 如果其他用户适当的访问权限位被设置,则允许访问。
1.3. setuid和setgid函数
在UNIX系统中,特权是基于用户和组ID的。当程序需要增加特权,或需要访问当前并不允许访问的资源时,我们需要更换自己的用户ID或组ID,使得新ID具有合适的特权或访问权限。与此类似,当程序需要降低其特权或阻止对某些资源的访问时,也需要更换用户ID或组ID,从而使新ID不再具有相应的特权或访问这些资源的能力。
一般而言,在设计应用程序时,我们总是试图使用最小特权(least privilege)模型。函数setuid设置实际用户ID和有效用户ID;函数setgid设置实际组ID和有效组ID。
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
关于改变用户ID的规则:
1). 如果进程具有超级用户特权,则setuid函数将实际用户ID、有效用户ID、以及保存的设置用户ID设置为uid。
2). 如果进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不改变实际用户ID和保存的设置用户ID。
3). 如果上面两个条件都不满足,则将errno设置为EPERM,并返回-1。
关于内核所维护的三个用户ID,还要注意以下几点:
1). 只有超级用户进程可以更改实际用户ID。实际用户ID实是用户登录时,由login程序设置的,而且永远不会改变它。因为login是一个超级用户进程,当它调用setuid时,会设置所有三个用户ID。
2). 仅仅当对程序文件设置了设置用户ID位时,exec函数才会设置有效用户ID。任何时候都可以调用setuid,将有效用户ID设置为实际用户ID或保存的设置用户ID。
3). 保存的设置用户ID是由exec复制有效ID而得到的。如果设置了程序文件的设置用户ID位,则在exec根据文件的用户ID设置了进程的有效用户ID以后,就将这个副本保存起来。
注意:getuid和geteuid函数只能获得实际用户ID和有效用户ID的当前值。改变三个用户ID的不同方法:
ID |
exec |
setuid(uid) |
||
设置用户ID位关闭 |
设置用户ID位打开 |
超级用户 |
非特权用户 |
|
实际用户ID |
不变 |
不变 |
设为uid |
不变 |
有效用户ID |
不变 |
程序文件的用户ID |
设为uid |
设为uid |
保存的设置用户ID |
从有效用户ID复制 |
从有效用户ID复制 |
设为uid |
不变 |
POIX.1包含了两个函数setuid和setegid。它们类似setuid和setgid,但只更改有效用户ID和有效组ID。
#include <unistd.h>
int seteuid(uid_t uid);
int setegid(gid_t gid);
转自: http://blog.csdn.net/youkuxiaobin/article/details/6876820