先摆出 main.c 文件, 回头再看.

#include "apue.h"
#include <fcntl.h>

int main(int argc, const char * argv[]) {

    if(argc != 2){
        err_quit("示例: ./a.out <filePath>");
    }

    const char * file_path = argv[1];

    //access函数以进程的 实际用户ID 为基础执行访问权限测试
    if(access(file_path, R_OK) < 0){
        err_ret("实际用户读权限检测失败!\n");
    }else{
        printf("实际用户读权限 is OK.\n");
    }

    //内核以进程的 有效用户ID 为基础执行访问权限测试
    if(open(file_path, O_RDONLY) < 0){
        err_ret("有效用户读权限检测失败!\n");
    }else{
        printf("有效用户读权限 is OK.\n");
    }

    exit(0);
}

测试目录下的文件

total 56
drwxr-xr-x  6 cbd   staff    204  8 21 16:44 ./
drwxr-xr-x  4 cbd   staff    136  8 21 15:58 ../
-rwsr-xr-x  1 root  staff  13644  8 21 16:42 a.out*
-rw-r--r--@ 1 cbd   staff    674  8 21 16:08 main.c
-rw-r--r--  1 cbd   staff     25  8 21 16:44 ordinary.txt
-r--------  1 root  staff     25  8 21 16:44 super.txt

在这里先只讨论用户组ID.

一个进程关联的用户ID可以有 实际用户ID有效用户ID 和保存的设置用户ID(exec函数调用,暂不讨论).

通常,实际用户ID在登陆系统的时候就确定了,有效用户ID大部分时候和实际用户ID一致.

可以用’who am i’查看实际用户, 用whoami查看有效用户.

用户以user1身份登陆,whoamiwho am i都是user1.

当用su切换到root之后,whoami为root, who am i还是user1.

(OSX默认root没有密码, 需要先sudo passwd root给root一个密码后才能su.)

内核以进程的有效用户ID为基础执行访问权限测试.

回到该目录, 重点看a.out文件, 它属于root用户.

super.txt属于root,而且只允许root用户读.

有没有办法在不改变super.txt文件属性的前提下,让一般用户使用a.out有读super.txt的权限呢?

这个例子就来自/etc/passwd的问题,它是敏感文件,只许root用户操作,但一般用户又需要passwd命令修改自己的密码.

解决办法就是在运行a.out的时候,把有效用户ID临时切换到root,也就是a.out的所属者.这个操作成为设置用户ID位.

Baodong-MBP:access_open cbd$ ll
total 56
drwxr-xr-x  6 cbd   staff    204  8 21 17:01 ./
drwxr-xr-x  4 cbd   staff    136  8 21 15:58 ../
-rwsr-xr-x  1 root  staff  13644  8 21 16:42 a.out*
-rw-r--r--@ 1 cbd   staff    828  8 21 17:01 main.c
-rw-r--r--  1 cbd   staff     25  8 21 16:44 ordinary.txt
-r--------  1 root  staff     25  8 21 16:44 super.txt
Baodong-MBP:access_open cbd$ ./a.out super.txt
实际用户读权限检测失败!
: Permission denied
有效用户读权限 is OK.

我们用cbd身份运行a.out, 该进程的实际用户ID为cbd.

看到rws中的s表示已经设置用户ID位,所以该进程的有效用户ID为该文件a.out的所有者也就是root.

内核在检查身份时以有效用户ID为准,所以有效ID为root的进程来查看只允许root用户查看的super.txt也就合法了.

另, rws表示只读+只写+执行+设置用户ID位; rwS表示只读+只写+设置用户ID位,没有执行权限.

另, rws------对应的数字mod为4700,---rwS------对应的数字mod为2060.(1为粘着位)

另, 在shell中可以这样设定 chmod u+s a.out, 注意s的对象为a.out这个可执行文件而不是想保护的那个文件.super.txt的权限设置永远不要改动.

权力越大责任越大,使用需谨慎.

总结

类型 shell 确定 检测
实际用户ID位 who am i tty时确定 access()
有效用户ID位 whoami su可变 system call