本篇内容是 su部分帐户免密码切换 的衍生篇。在LINUX下有4个UID:RUID(real user id)、EUID(effective user id)、SUID(saved user id)、SUID(set user id),其具体区别如下:

  • RUID, 用于在系统中标识一个用户是谁,当用户使用用户名和密码成功登录后一个UNIX系统后就唯一确定了他的RUID;
  • EUID, 用于系统决定用户对系统资源的访问权限,通常情况下等于RUID;
  • SUID(set user id),用于对外权限的开放。跟RUID及EUID是用一个用户绑定不同,它是跟文件而不是跟用户绑定。
  • saved uid,这个实际上是一个虚拟概念,其对应的实际上还是RUID和SUID,只是在不同身份之间切换时变成对应的值 。

这里举个例子,比如我们常用的passwd改密码命令,普通用户是可以执行的,大家都知道其有s权限位:

1[root@361way ~]# ll  /usr/bin/passwd
2-rwsr-xr-x. 1 root root 27832 Jun 10  2014 /usr/bin/passwd

假如现在user1想要改密码,user1的RUID是user1,当其调用passwd命令的时候,其有效身份EUID实际为root ,而set user id 就是对应的前面的passwd上的 s 权限位,而saved uid 是中间态 。这个中间态是怎么理解的呢?

当user1执行平时的大多数命令时,其对应的都是RUID,修改一个文件后,对应文件的属主就是user1。而当其调用passwd这个命令修改密码时(passwd修改完成后会更改/etc/shadow里的值),其临时获取了root权限用于修改自身密码,但他修改完成后/etc/shadow文件的属主还是root ,不是user1,对吧!所以saved uid这个中间态你大值就可以这样理解,平时情况下saved user id = RUID,但在遇到set user id这种情况下,saved user id = EUID 。

下面来一段C代码,可以看下这个ID的变化:

 1#include <sys/types.h>
 2#include <unistd.h>
 3#include <stdio.h>
 4int main()
 5{
 6    printf("real uid is %d\n", getuid());
 7    printf("effective uid is %d\n", geteuid());
 8    getchar();
 9    if (seteuid(1001) == -1)    /* zzz = 1001 */
10    {
11        perror("seteuid");
12        return -1;
13    }
14    printf("real uid is %d\n", getuid());
15    printf("effective uid is %d\n", geteuid());
16    getchar();
17    if (seteuid(0) == -1)       /* root = 1001 */
18    {
19        perror("seteuid");
20        return -1;
21    }
22    printf("real uid is %d\n", getuid());
23    printf("effective uid is %d\n", geteuid());
24    getchar();
25}

编译代码, 并把可执行文件的属主改为root, 然后添加上set-user-ID位:

1gcc uid.c -o uid
2sudo chown root:root uid
3sudo chmod u+s uid

执行该程序后,输出如下:

1real uid is 1001
2effective uid is 0
3real uid is 1001
4effective uid is 1001
5real uid is 1001
6effective uid is 0