UNIX系统为了总是以最小特权去执行一个程序,给出了setuid和setgid函数原型如下:
#include<unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
用户ID和组ID的更改规则是相通的,大家可以举一反三,下面写的都是关于用户ID的,组ID一样的原理。
一个进程有自己的
实际用户ID(谁的程序)
有效用户ID(执行其他程序时的权限)
设置用户ID(由exec复制有效用户ID得来的)
谁能更改用户ID:
exec函数
setpid
修改ID(用户ID或者组ID)的一些规则:
1、如果进程拥有root,也就是超级用户权限,那牛掰了,只要该进程执行setuid函数就可以将自己的,实际用户ID、有效用户ID、以及稍后会提到的保存的设置用户ID更改为参数uid。
2、若进程只是普普通通的“老百姓”,UNIX的普通用户,那该进程只能改变自己的有效用户ID,而这个有效用户ID是会跟自己的实际用户ID或者设置用户ID一样。也就是说,普通用户进程执行setuid函数,参数跟自己的实际用户ID 或者 设置用户ID 一致。(可以了解到,普通用户只可以更改自己的有效用户ID,而且改也只能改成实际ID或者设置ID)
3、以上两种都不满足的,执行setuid函数就会出错。
三个用户ID的特点:
1、只有超级用户的进程可以更改实际用户ID
2、这里又引入了一个叫做 设置用户ID位 的概念,只有这一位设置了,exec才会设置用户ID
但是setpid函数没有这个限制,任何时候都可以通过setpid函数来把有效用户ID设置成实际用户ID或者设置用户ID
3、保存的设置用户ID 来自exec复制有效ID得来的,
关于设置用户ID:
以我们的进程执行 man程序为例;
man程序的实际用户ID是man,有效用户ID也是man,:1、我们要执行man命令 2、man也要执行命令;
1、首先我们的进程要执行man命令,所以exec把我们进程的有效用户ID给改了,改成man了,并且复制了man给设置用户ID,然后我们就可以顺利执行man命令了。
此时我们进程的ID:
实际用户ID = 我们的用户ID
有效用户ID = man(为了执行man命令)
保存的设置用户ID = man(exec设置的)
2、我们的进程要求man执行其他命令,但是现在我们的有效ID是man,所以需要更改有效ID为我们进程的实际ID,调用setuid(getuid())函数
实际用户ID = 我们的用户ID
有效用户ID = 我们的用户ID(setuid改的)
保存的设置用户ID = man
3、man执行完我们的命令之后,会改变有效用户ID为man
实际用户ID = 我们的用户ID
有效用户ID = man
保存的设置用户ID = man
这时我们发现了保存的设置用户ID在ID转换过程中的作用!实际用户ID是不变的,确保我们可以将有效用户ID改成实际用户ID。在exec新程序之后,会引入新程序的有效用户ID,保存为设置用户ID,这样进程的有效用户ID也可以改成新程序的有效用户ID。