在做毕设的时候,碰到了一个场景:需要在普通用户的情况下调用“特权程序”,来访问受保护的文件。相应知识网络安全课学过,这里再回忆并总结一下。
在Unix的设计中,进程与多个用户ID和用户组ID相关联,包括如下:
1、实际用户ID和实际用户组ID:标识我是谁,身份的识别,谁运行的程序。也就是登录用户的uid和gid,比如我的Linux以simon登录,在Linux运行的所有的命令的实际用户ID都是simon的uid,实际用户组ID都是simon的gid(可以用id命令查看)。
2、有效用户ID和有效用户组ID:进程用来决定我们对资源的访问权限,权利的识别。一般情况下,有效用户ID等于实际用户ID,有效用户组ID等于实际用户组ID。在操作系统中,用euid表示有效用户id。
当设置(SUID)位时,则有效用户ID等于文件的所有者的uid;同样,如果设置了(SGID)位,则有效用户组ID等于文件所有者的gid。也就是说,不论是哪个用户使用该文件,该文件都拥有等同于其创建者(往往是root)的权限。
进程的RealUID和EffectiveUID 以及进程UID的继承关系
一. 身份的标识: Real UID
* 进程的UID只是泛称, 其实有很多种UID(ruid / euid)
* 进程的 Real UID 是进程身份的标识, 用来说明Who am I, 没有实权
* 进程的权限并不是由RealUID来决定的
二. 权限的标识: Effective UID
* 有身份无权限是不行的, 有权限才能为所欲为
* Effective UID 是进程的权利的标识, 标识了该进程的“权利”
* Linux的授权 是 靠 Effective UID 来识别的
* 有权利就能做一切
* 之前说明的,文件、资源以及特权API操作权限 是 通过 Effective UID来识别的
三. 身份和权利的关系
* 默认情况下 Real UID == Effective UID, 所以使用ps命令输出的 就是 Effective UID
* 我们也可以显示完整的 Effective UID 和Real UID
四. ROOT 用户的特权
* Root 用户, 均是指 Effective UID == ROOT的进程
* 不受任何限制,可以为所欲为
* ROOT进程可以调用setUID 修改自己的Real UID,它也可以把自己的Effective UID改为普通的UID。
五. UID的世袭
* 在Linux世界里,为了安全考虑,UID世袭规则: 身份可以世袭,权利不能世袭
* 子进程的 Real UID = Effective UID, 继承 父进程的Real UID
若父进程的Effective UID 与 Real UID 不一样,则不具有父进程的权利
六、文件的setUID – 文件的setUID标志以及其作用。
临时提升某可执行文件的euid到owner id,同时不需要改变其ruid。这样,普通用户也可以做某些特权行为。
6.1 需求:
* Linux的passwd是一个可执行程序, 用于修改用户的密码
* passwd需要修改多用户的账号文件(该文件仅能ROOT用户可以读写)
* 但是 普通用户 也要修改自己的密码
* passwd虽然 是平民身份(由普通用户启动),但是却需要皇族的权限 ---- 身份 和 权利不同
6.2 解决:
* 临时提升进程的Effective UID, 而维持身份不变(Real UID), 让他能够利用特权,而又不传给子进程
/*
* getuid() returns the real user ID of the calling process.
* geteuid() returns the effective user ID of the calling process.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
char * get_username_by_id(uid_t uid)
{
struct passwd *pwd;
pwd = getpwuid(uid);
return (pwd == NULL) ? NULL : pwd->pw_name;
}
int main(int argc, char *argv[])
{
int fd;
fd = open(argv[1], O_RDWR);
if(fd == -1)
perror("Open fail: ");
else
printf("Open %s ok.\n", argv[1]);
printf("Real User ID:%d, name=%s\n",
getuid(), get_username_by_id(getuid()));
/* 如果设置了Set-User-ID(chmod u+s),那Effective User ID与Owner ID相同。 */
printf("Effective User ID:%d, name=%s\n",
geteuid(), get_username_by_id(geteuid()));
close(fd);
return 0;
}