作者:林世霖,华清远见嵌入式学院讲师。
关于unix系统中涉及权限的问题探讨,跟大家分享下
首先要明白一个关键点----权限分为两种:
第一种是用ls -l命令显示出来的文件性质的权限,比如 -rw-r--r-- foo foo file,这里的读写权限是该文件本身的性质,表示该文件本身属于foo用户,属于foo组。
第二种是进程性质的权限,比如 -rwsr--r-- bar bar file,这个file文件本身属于bar用户,但是由于设置了用户设置ID,导致如果以foo用户来执行该文件的话,进程的有效用户ID就不是foo而是bar,该进程以bar的权限运行。
一个静态程序文件在磁盘中存在时,它只有文件性质的权限,即用户ID和用户组ID;当该静态程序被加载进内存运行时,它就不仅要考虑之前的两个所有者 ID,而且还应考虑执行它的用户的ID(该文件的所有者和当前该文件的执行者当然可以不同),那么内核究竟要用哪些ID作为该进程运行时的有效ID呢?
设置ID (包括设置用户ID和设置组ID)就是用来回答这个问题的:
1、如果一个文件被设置了设置用户ID,那么无论该文件的执行者是谁,进程的有效用户ID == 所有者ID,否则有效用ID == 执行者ID。
2、如果一个文件被设置了设置组ID,那么无论该文件的执行者是谁,进程的有效组ID == 所有者组ID,否则有效组ID == 执行者组ID。
3、一个文件的其他组ID没有必要被设置,因为如果执行者ID本身既不拥有该文件,也不属于该文件所在的组,就必然在其他组,此时再设置“设置其他组ID”显然毫无意义。
把以下步骤在你的机器上执行一遍,相信你对这些乱七八糟的权限一定会更加了然于心:
0、以用户foo登录(当然你可以用其他你可以用的用户登录,只是这里我们要用到两个用户,这是第一个)。
1、写一个创建普通文件的程序creat_file.c:(为了简洁,我把出错处理的代码统统扔掉了)。
________________________________________
#include <stdio.h>
#include <fcntl.h>
int
main(int argc, char **argv){
int fd;
fd = open("candy", O_CREAT|O_EXCL|O_RDWR, 0644); //创建一个叫做candy的普通文件,这里的0644是文件的权限
char buf[]="okay, you can have my candy.";
write(fd, buf, sizeof(buf)); //往文件里边儿随便写进一句话
return 0;
}
________________________________________
2 、编译它生成a.out可执行程序,并将它们放在一个叫test的文件夹里面。
此时:test目录和其下面的creat_file.c源程序、a.out可执行程序,而且它们的具体属性如下图所示:
从图中看到:它们都没有设置ID,都属于foo用户和foo用户组
3、因为待会儿我们要用另一个用户seton执行a.out,为了让其他用户执行a.out时拥有跟foo一样的权限,我们用命令chmod u+s a.out为a.out程序设置用户ID。一切ok之后我们用seton用户执行a.out,生成一个文件candy,各个文件具体情况如下图所示:
注意到图中a.out的用户ID已经被设置了(执行位显示为小s),此时产生的文件candy属于foo用户,且属于seton用户组,原因是:一 个由进程创建的新文件,其用户ID取决于进程的有效ID,在这里我们虽然是以用户seton来执行a.out的,但是a.out被其所有者foo设置了用 户ID,因此a.out进程执行时的有效ID就是foo,因此由a.out所创建的文件candy就属于用户foo。
另外,candy属于用户组seton的原因是因为a.out所在的目录test没有被设置用户组ID(可以看到test的用户组执行位是小x而不是小s)。在这种情况下新创建文件的用户组ID等于进程的有效组ID。
4、接下来我们改变test的用户组设置ID,看看会发生什么情况:
由于更改了test的用户组设置ID,此时由a.out进程创建的文件candy的用户组变成了foo而不再是seton了。
应该注意的是,对于进程创建的文件的用户组属性,以上讨论仅限于linux和solaris实现,而对于mac和freeBSD而言情况更加简单,它们不在乎进程的有效用户组ID是什么,由该进程创建的新文件的用户组ID一律等于进程所在目录的用户组ID。
我们从stat结构体读取的st_mode是文件的实际用户(组)ID权限。就是 ls -l出来的这些:-rw-r--r--
进程对文件的操作时,内核用的是有效用户(组)ID来测试的权限问题的,前面讲过,有效用户(组)ID是进程的属性,当文件没有设置设置用户(组)ID的时候,它就等于实际用户(组)ID,当设置了设置用户(组)ID时它就等于设置用户(组)ID。
(顺便在提一点,小s表示该文件的所有者具有执行权限且该文件被设置了相应的设置位权限,大S表示该文件的所有者没有执行权限但该文件被设置了相应的设置位权限……是不是有点拗口 -_-!)
另外不得不提的是umask, 虽然open函数可以为新创建的文件指定各用户对应的权限,但这是受限于umask的当前值的。只要权限屏蔽字umask中被置位的位就一定被关闭,即使 open参数指定要打开。例如umask的值为022,那么无论open中参数如何设置,组用户和其他用户对该文件都不具备写权限。(实际上open里的 参数模式值将会与umask屏蔽字的反码做“与”操作)
另外,umask接受的参数不一定是八进制,比如可以写成umask(0644)或者umask(234)或者umask(0x2ff),实际上umask会把参数统统转换成二进制数并且只取最低9位作为有效数据。
文章评论(0条评论)
登录后参与讨论