关于Linux文件访问权限与设置用户id位
最近在学习《Unix 高级环境编程》这边书,之前对Unix中的文件访问还有和文件访问相关的设置用户id(set_user_ID)位以及设置组id(set-group-ID)位一直没有弄清楚,今天跟他人讨论一个问题,终于有些明白了,记录以供温故。
首先说说文件的权限控制位,每一个文件都有文件模式字st_mode,ls -l一个文件前面10位就是文件的类型和权限说明了。具体可分为用户读写可执行,组读写执行,其他读写执行位。当一个进程要访问某个文件的时候,会以进程的有效用户ID来进行权限检测,看改用户ID具体属于文件的哪个部分,是文件用户本身,还是属于用户组还是属于其他用户的。与每个进程相关联的用户ID和组ID包括实际用户(实际上是谁),ID实际组ID;有效用户ID(用于文件访问权限检查),有效组ID,附加组ID(有时候一个用户可能属于多个组);保存的设置用户ID(由exec函数保存),保存的设置组ID。所有者ID是文件的性质,而有效ID和附加组ID是进程的性质。一般内核进行的检测是:
(1)若进程的有效用户ID是0(超级用户),则允许访问。
(2)若进程的有效用户ID等于文件的所有者ID(即进程拥有此文件),那么当所有者适当的访问权限位被设置,则允许访问,否则拒绝访问。适当的访问权限位指的是,若进程为读而打开该文件,则用户读位应为1,若进程为写而打开该文件,则用户的写位应为1。。。
(3)若进程的有效用户ID或进程的附加组ID之一等于文件的组ID,那么:若组的适当的访问权限位被设置,则允许访问,否则拒绝访问。
(4)若其他用户适当的访问权限位被设置,则允许访问,否则拒绝访问。
按顺序执行这四步,若进程拥有此文件(第2步),则按用户访问权限批准或拒绝该进程对文件的访问,不查看组访问权限。类似地,若进程并不拥有该文件,但进程属于某一个适当的组,则按组访问权限批准或者拒绝该进程对文件的访问,不查看其他用户的访问权限。当进程既不拥有该文件,进程也不属于某个组,就只能查看其他用户的访问权限了。
当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID通常就是实际组ID。但是当文件设置了用户ID位后,当执行此文件时,将进程的有效用户ID设置为文件所有者的用户ID(st_uid),设置组ID类似。下面将以一个例子来具体说明,其中access函数是按照实际用户ID和实际组ID进行访问权限测试的,open函数打开一个文件事,内核以进城的有效用户ID和有效组ID为基础进行权限测试。
access函数实例:
#include "apue.h" #include <fcntl.h> int main(int argc, char *argv[]) { if (argc != 2) err_quit("usage: a.out <pathname>"); if (access(argv[1], R_OK) < 0) err_ret("access error for %s", argv[1]); else printf("read access OK\n"); if (open(argv[1], O_RDONLY) < 0) err_ret("open error for %s", argv[1]); else printf("open for reading OK\n"); exit(0); }
编译生成可执行文件a.out并执行:
chardliu@ubuntu:~/apue.2e/file$ cc access.c
chardliu@ubuntu:~/apue.2e/file$ ls -l a.out
-rwxrwxr-x 1 chardliu chardliu 7839 Jun 26 21:01 a.out
chardliu@ubuntu:~/apue.2e/file$ ./a.out a.out
read access OK
open for reading OK
root@ubuntu:/home/chardliu/apue.2e/file# ll /etc/shadow
-r-------- 1 root shadow 1235 Apr 11 18:50 /etc/shadow
chardliu@ubuntu:~/apue.2e/file$ ./a.out /etc/shadow
access error for /etc/shadow: Permission denied
open error for /etc/shadow: Permission denied
此时之所以access和open都出错,是因为进程的实际用户ID和有效用户ID都为chardliu,而shadow文件的用户所有者是root,所以当进程以chardliu身份来对shadow文件进行访问权限检测时,是根据shadow的其他用户读写执行位来检测的,由上可知,shadow文件只有所有者root本身可读,没有其他任何权限。
按理,那么当给shadow文件增加其他用户读权限后access和open都应该成功,测试一下果真如此:
chardliu@ubuntu:~/apue.2e/file$ su //以root用户对shadow文件进行权限设置
Password:
root@ubuntu:/home/chardliu/apue.2e/file# chmod o+r /etc/shadow //给shadow增加其他用户可读权限
root@ubuntu:/home/chardliu/apue.2e/file# exit
exit
chardliu@ubuntu:~/apue.2e/file$ ll /etc/shadow
-r-----r-- 1 root shadow 1235 Apr 11 18:50 /etc/shadow
chardliu@ubuntu:~/apue.2e/file$ ./a.out /etc/shadow //再次访问shadow文件,OK
read access OK
open for reading OK
下面说明一下设置用户ID的作用。
在此之前还是将shadow的文件访问控制位置为原来的,即清除其他用户可读权限,同时将a.out可执行文件的所有者改为root,并且设置其用户ID位:
chardliu@ubuntu:~/apue.2e/file$ su
Password:
root@ubuntu:/home/chardliu/apue.2e/file# chmod o-r /etc/shadow
root@ubuntu:/home/chardliu/apue.2e/file# ll /etc/shadow
-r-------- 1 root shadow 1235 Apr 11 18:50 /etc/shadow
root@ubuntu:/home/chardliu/apue.2e/file# chown root a.out
root@ubuntu:/home/chardliu/apue.2e/file# chmod u+s a.out
root@ubuntu:/home/chardliu/apue.2e/file# ll a.out
-rwsrwxr-x 1 root chardliu 7839 Jun 26 21:01 a.out*
退出超级用户,以正常用户运行:
root@ubuntu:/home/chardliu/apue.2e/file# exit
exit
chardliu@ubuntu:~/apue.2e/file$ ./a.out /etc/shadow
access error for /etc/shadow: Permission denied
open for reading OK
会发现运行结果access失败,而打开文件成功。access是以实际用户IDchardliu对shadow进行访问权限检测的,发现其他用户读没有设置权限,所以失败;a.out设置了用户ID,所以当进程执行a.out时,进程的有效用户ID由chardliu设置为了a.out所有者的用户ID root了,所以可以成功打开文件,open是以进程的有效用户ID进行访问权限检测的。
通过这个过程,相信会对文件的访问权限控制有一个比较清晰的理解。
参考资料:W.Richard Stevens, Stephen A.Rago《UNIX环境高级编程》