1 进程相关ID
除了进程ID外,与进行相关的ID主要有六个:实际用户ID、实际组ID、有效用户ID、有效组ID、附加组ID、保存的设置用户ID、保存的设置组ID。
- 实际用户ID和实际组ID标识进程是属于谁的。这两个字段在登入时取自口令文件中的登入项。
- 有效用户ID,有效组ID以及附加组ID决定了进程对文件的访问权限。
- 保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。
通常在执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID就是实际组ID。在文件模式st_mode中设置一个特殊的标志,其含义是“当执行文件时,将进程的有效用户ID设置为所执行文件的所有者的用户id”。类似,还可以设置另一个特殊标志,使得将执行此文件的进程的有效组ID设置为文件的组所有者ID。这两个特殊标志位被称为设置用户ID位和设置组ID位。
2 更改进程相关ID
当程序需要增加特权,或者需要访问当前并不允许访问的资源时,我们需要更换自己的用户ID或组ID,是的新ID具有合适的特权或访问权限。类似地,当程序需要降低其特权或阻止对某些资源的访问时,也需要更换用户ID或组ID,从而使新ID不能具有相应的特权或访问资源的能力。
可以用函数setuid来设置实际用户ID和有效用户ID。类似地,可以用函数setgid设置实际组ID和有效组ID。这两个函数要能调用成功,必须符合下列两个条件之一(下面说的都是针对修改用户ID的,对于修改组ID的情况是类似的,也有类似的函数来修改组ID),否则调用将会失败:
- 若进程具有超级用户权限,则setuid(uid)函数将实际用户ID、有效用户ID、以及保存的设置用户ID都设置为uid。
- 若进程没有超级用户权限,但是uid等于实际用户ID或者保存的设置用户ID,则setudi(uid)只将有效用户ID设置为uid。不改变实际用户ID和保存的设置用户ID。
关于内核所维护的三个用户ID,应该注意一下三点:
- 只有超级用户进程可以更改实际用户ID。通常,实际用户ID是在用户登入时,由login程序设置的,而且永远不会改变。因为login是一个超级用户进程,当它调用setuid时,会设置所有三个用户ID,这也是setuid为什么存在条件一的原因。
- 仅当对程序文件设置了用户ID位时,exec函数才会设置有效用户ID。如果设置用户ID位没有设置,则exec函数不会改变有效用户ID,而将其维持为原先值(子进程继承父进程的)。任何时候都可以调用setuid,将有效用户ID设置为实际用户ID或者保存的设置用户ID。当然,不能将有效用户ID设置为任意值。
- 保存的设置用户ID是由exec复制有效用户ID而得到的。如果设置了文件的设置用户ID位,则在exec根据文件的用户ID设置了进程的有效用户ID后,就将这个副本保存到保存的设置用户ID中。
改变三个用户ID的方法如下表所示:
ID | exec | setuid(uid) | ||
设置用户ID位关闭 | 设置用户ID位打开 | 超级用 | 非特权用户 | |
实际用户ID | 不变 | 不变 | 设为uid | 不变 |
有效用户ID | 不变 | 设置为程序文件的用户ID | 设为uid | 设为uid |
保存的设置用户ID | 从有效用户ID复制 | 从有效用户ID复制 | 设为uid | 不变 |
还可以用setreuid来交换实际用户ID和有效用户ID的值。它的规则也比较的简单:一个非特权用户总能够交换实际用户ID和有效用户ID。这就允许一个设置用户ID程序转换成只具有用户的普通权限,以后又可再转换回设置用户ID所得到的额外权限。
还可以用函数seteuid来改变有效用户ID,它和setuid类似,不过只能改变有效用户ID。下图中给出了修改用户id的各个函数。