转自 http://blog.csdn.net/todd911/article/details/16370577
在unix系统中,特权是基于用户和组ID的,当程序需要增加特权,或需要访问当前并不允许访问的资源时,我们需要更换自己
用户ID或组ID,使的新ID具有合适的特权或访问权限。与此类似,当程序需要降低其特权或阻止对某些资源的访问时,也需要
更换用户ID或组ID,从而使新ID不具有相应特权或访问这些资源的能力。
可以用setuid函数设置实际用户ID和有效ID,与此类似,可以使用setgid函数设置实际组ID和有效组ID。
[cpp] view plaincopy
- #include <unistd.h>
- int setuid(uid_t uid);
- int setgid(gid_t gid);
- //两个函数返回值:若成功则返回0,出错则返回-1。
POSIX.1包含了两个函数seteuid和setegid,它们类似于setuid和setgid,但是只更改有效用户ID和有效组ID。
[cpp] view plaincopy
- #include <unistd.h>
- int seteuid(uid_t uid);
- int setegid(gid_t gid);
- //两个函数返回值,若成功则返回0,出错则返回-1.
关于改变用户ID的规则如下:(用户ID所说明的一切都适用于组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程序设置的,而且永远不会改变它。
2.仅当对程序文件设置了设置用户ID位后,exec函数才会设置有效用户ID。任何时候都可以调用setuid,将有效用户ID设置为实际
用户ID或保存的设置用户ID。自然,不能将有效用户ID设置为任何随机值。
3.保存的设置用户ID是由exec复制有效用户ID而来的,如果设置了文件的设置用户ID,则在exec根据文件的用户ID设置了进程的有效
用户ID后,将这个副本保存起来。
下表列出了改变这三个用户ID的不同方法。
下面通过一个例子说明保存的设置用户ID的用法。
man程序可能要执行许多其他命令,以处理包含需显示手册页的文件。为了防止被欺骗运行错误的命令或重写错误的文件,man命令
不得不在两种权限之间切换:运行man命令用户的权限,以及拥有man可执行文件用户的权限。下面是其工作步骤:
1.man程序文件是由名为man的用户拥有的,并且其设置用户ID位已设置。当我们exec此程序时,关于用户ID得到:
实际用户ID=我们的用户ID
有效用户ID=man
保存的设置用户ID=man
2.man程序访问需要的配置文件和手册页,这些文件是由名为man的用户所拥有的,因为有效用户ID是man,所以
可以访问这些文件。
3.在man代表我们运行任一命令后,它调用setuid。因为我们不是超级用户进程,所以仅仅改变有效用户ID。此时:
实际用户ID=我们的用户ID
有效用户ID=我们的用户ID(已改变)
保存的设置用户ID=man
现在,man进程是以我们的用户ID作为其有效用户ID而运行的。它可以代表我们安全地执行任意过滤器程序。
4.当执行完过滤器操作后,man调用setuid(euid),其中euid是用户man的数值用户ID。因为setuid的参数等于
保存的设置用户ID,所以这种调用时允许的。现在得到:
实际用户ID=我们的用户ID
有效用户ID=man(已改变)
保存的设置用户ID=man
5.因为man程序的有效用户ID是man,所以现在它可对其文件进行操作。
//这个步骤好复杂啊...