|
小谈Linux文件权限及一些延展
学习Linux一年有余,虽然至今尚无法一窥它的精髓,不过对于某些方面的内容还是有做一番总结的资本,况且总结,即是梳理的过程,通过梳理,能够加深对Linux的理解。
如果你还在因为你电脑中的操作系统越来越慢而每周进行磁盘整理的话,我相信Linux的文件系统会在这些方面大大的令你感到满意,我没有打算也没有实力告诉你ext3、reiserfs与fat32、ntfs之间相比究竟有哪些物理上的区别,但是我可以告诉你,一台终年365*24运行的Linux的的确确不需要花任何时间进行碎磁盘整理,甚至,Linux根本没有提供这样的工具。
有很多人在报怨Linux没有Windows好用,借用我看过的一篇帖子的话来说,那是因为你中了M$的毒,倘若过去你从来都没有接触过Windows,倘若你心爱的PC机上安装的第一个操作系统就是Slackware、Debian或是RedHat,我想多年后你再见识到Windows的时候想法会有180度的转变吧,兴许你会说:“这东西是不是送给小孩儿的游戏机?”事实上,我现在就是使用Linux系统中的文字处理软件OpenOffice写这篇文章的,而且现在我还深信了一点,那就是:Windows能做但是Linux无法做的,那就是不需要做的。还有许多证据表明,Linux在性能方面远远领先于动辄宕机的Windows,现在我还没有资格对这一结论加上自己的证据,但是有一点我很清楚,那就是Linux(更准确的说是Unix)的文件系统设计比Windows高明得多。
由于这篇文章不是要讨论Linux如何超越Windows,所以我很快就谈到了文件系统。就我个人的理解,文件系统即是操作系统的土壤,操作系统所需要的文件组织与结构便是由文件系统全权决定的。比如Linux系统中,一般有所谓目录组织,即从根目录开始,形成一种倒树状结构,这样的结构便是文件系统的一部分,它可以告诉操作系统如何找到相应文件并进行处理。文件系统的另一大特点是规定了各种类型文件所代表的对象,比如文本、声音、图象等等,Linux文件系统的又一大特色是,它将所有这些对象都视为文件,普通文件、设备文件、管道文件......也就是说,你的任何操作实际上都是针对某些文件在进行。而说到文件,就引出我们今天讨论的核心问题------文件权限。在Linux中,你可以找到的任何文件都会针对三种不同的集合进行权限分配,这三种集合是:owner(所有者)、group(用户组)、others(其他),相应的,每种集合在对文件进行操作的过程中会由于该文件赋予其的不同权限而产生不同的效果。比如用户A能进入某个目录(目录也被视为文件),但是用户B却不能,这里便是文件权限在起作用了。那么如何获知某个文件赋予相应集合的权限呢?首先我们需要了解一个命令:ls。使用过DOS的用户应该知道,若想浏览某一目录中的内容可以使用dir这个命令,而Linux中的ls命令的作用便和dir差不多。先让我们找个文件来做示范。在我的系统中,/home/test/目录下有一个文件叫test,让我们使用ls来看看屏幕输出的信息:
root@x-force:/# ls -l /home/test/test
-rw-r--r-- 1 root staff 0 2005-06-10 15:59 /home/test/test
注意看ls命令的显示信息,可以发现在第一列有一串字符:-rw-r—r--,这一串字符就是该文件的权限说明。首先我们将该字符串分为10位、四组,第一组是最左的一位,第二组是rw-,第三组是r- - ,第四组是剩下的r- - 。先介绍第一组,"-”代表该文件是一个普通文件,常见的还有'b'、'c'和'd'。'b'代表改文件是一个块设备,'c'代表该文件是一个字符设备,'d'代表该文件为一个目录。块设备和字符设备即组成Linux的设备文件。块设备一般是指具有块传输属性的硬件设备,如磁带机、磁盘等;而字符设备包括像终端设备、调制解调器和不用块传输的打印机等。所谓块传输,即是文件系统事先在硬盘分区中划分好一定大小的存储空间,称为块,然后块设备以固定的块为单位进行数据传输;而字符设备的数据传输就不是以固定的块为单位,而是以字节流形式进行,字节流可以为任意长度。值得注意的是,虽然硬盘一般为块设备,但是在某些场合,它却是字符设备。如果某个硬盘分区属于字符设备,那么文件系统就不能再挂载上去了。现在你应该大致理解了第一组字符代表的意思了,接着我们来看第二组:rw-,它包含三位,第一位是字母r,这个字母其实是“read”的缩写,也即是代表可读的意思,同样,第二位w是“write”的缩写,代表可写,第三位出现了一个很奇怪的符号:-- ,这个符号实际上屏蔽了本来的第三位--- ’x‘ ,x是“execute”的缩写,代表了可执行,但是这里它被短横线屏蔽了,也就是说,test文件不能够执行(不具备可执行的属性)。由此可见,实际上一个文件如果是满权限的话,那么第二组的三位字母应该为“rwx”。聪明的人也许这时已经可以自己看出第三组和第四组代表怎样的权限了。其实第三组和第四组所代表的权限是相同的:r- - ,第一位r代表可读,第二位和第三位原本分别该是w和x的,但是这里被'--'屏蔽了,也就是说,第三组和第四组代表的权限即是可读不可写不可执行,这样说比较拗口,可以简短的称为只读。那么,你可能会问,为什么一个文件会出现三组不同的权限呢?比如在这个例子里面就出现了可读可写、只读、只读这三组权限。其实你如果用ls命令查看任何一个文件都会发现它是由10位字符组成的,第一位字符不用再解释了,但是为什么该文件会出现三组不同的权限组合呢?回忆前面看到的:“在Linux中,你可以找到的任何文件都会针对三种不同的集合进行权限分配,这三种集合是:owner(所有者)、group(用户组)、others(其他)”,所以,以test文件为例,三组不同的权限组合:可读可写、只读、只读分别赋予了Linux的三种集合:所有者、用户组、其他。也就是说,test文件只有该文件的所有者可读可写,用户组的成员只读,其他用户只读。所有者和用户组又如何获知呢?参看上面的输出,第三列和第四列就分别代表了所有者和用户组,在这里,root就是test文件的所有者,而staff即是test文件的用户组,也就是说,root用户对test文件可读可写,而所有属于staff组的用户只读test文件,其他用户只读test文件。看到这里,你也许以为自己已经掌握文件权限了,但是别高兴的太早,沉下心来想想这几个问题:究竟可读(r)、可写(w)、可执行(x)赋予的是什么权限、在对各种不同文件操作的过程中这些权限起着怎样的作用、它们更深一层的意义是什么?下面,我会以几个例子来对文件权限做更深一层的探讨。Let's go on!
例一.你使用ls命令查看文件test ,发现输出内容如下,已知用户test属于用户组test ,那么,用户test究竟对文件test拥有可读可写权限还是只读权限呢?
root@x-force:/# ls -l /home/test/test
-rw-r--r-- 1 test test 0 2005-06-10 15:59 /home/test/test
这个问题虽然很简单,但是一定要清楚:文件所有者的权限将覆盖文件用户组的权限。说简单点,就是test用户虽然属于test组,但是由于他是文件所有者,所以他应该继承文件所有者的权限,所以,test用户的权限应该是rw-,如果test用户组中存在另外一个用户tes ,那么他的权限才会继承test组的权限,即是r- - (只读)。
例二.使用ls命令分别查看目录/home/test/和该目录中的文件test ,发现输出内容如下,那么使用用户test能否删除test文件?
root@x-force:~# ls -dl /home/test/
dr--r--r-- 2 test test 4096 2005-06-10 15:59 /home/test/
root@x-force:/# ls -l /home/test/test
-rw-r--r-- 1 test test 0 2005-06-10 15:59 /home/test/test
这个问题的答案是:不能。也许你很快就能发现,test用户对于目录/home/test/并没有w权限,你会猜到这也许就是问题的原因。你猜的没错。不过你能说清楚到底目录权限和目录中的文件权限的联系是什么吗?比如现在我给目录/home/test/赋予可写权限,我想让你再次回答例二的问题,也许你会毫不犹豫的说,这次肯定可以了,不过我告诉你,还是没有完全正确。给test用户赋予目录/home/test/的写权限,如果你直接使用命令:rm /home/test/test ,那么你就可以成功删除该文件了。但如果你今天不用这种方法,你偏偏想这样删除test文件:首先cd /home/test/,然后rm ./test ,那么你会发现,此路不通。因为你根本无法进入/home/test/这个目录!下面我来给出目录文件权限的含义:
1.目录读权限:表明对应某个集合(所有者,用户组用户,其他用户)具有列出该目录下所有文件和子目录名的权限。但是这并不意味着该类集合具有读取这些文件内容的权利,要想读取文件内容,需要该文件打开可读权限。也就是说,如果/home/test/目录对用户test开放了读权限,则test用户可以通过命令 ls -l /hoem/test/查看test目录里面有什么内容,如果没有开放读权限,则 ls对test目录无效。
2.目录的写权限:表明对应某个集合具有在该目录下创建新文件和删除已有文件的权限。同样,这并不意味着该类集合具有修改这些文件内容的权限,除非文件打开了写权限。但事实上我们可以通过把目录下的一个已经存在的文件删除,然后再创建一个同名文件来达到修改原文件的目的,这也是Linux文件权限的瑕疵吧。
3.目录的执行权限(也称搜索权限):允许相应集合进入该目录,比如用cd命令等。另外,如果用户要打开一个文件,则必须拥有该文件所在绝对路径上所有目录的可执行权限。比如,test用户想使用cat命令查看/home/test/test这个文件的内容,那么除了要求test用户具有/home/test/test文件的可读权限,同时还要求test用户被赋予/home/目录和/test/目录的可执行权限。
现在你应该清楚目录的权限和目录里文件的权限之间的联系了吧。自己做些假设,说不定还有迷糊的地方呢!
如果前面的内容你真的搞清楚了,我们来看看更进一步的。
例三.使用ls命令查看shell命令passwd的输出信息如下:
root@x-force:~# ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 24248 2003-04-26 21:50 /usr/bin/passwd
很明显,该文件属于用户root ,并且权限为rws,但是第三位怎么会是's'而不是'x'呢?
要说清楚这个问题,我们先从有效用户和有效组说起。确切的说,与进程创建的文件有关的用户就是有效用户。比如,用户test使用shell命令vi创建一个文件a,ls查看该文件信息,会发现该文件的拥有者就是用户test,那么用户test就是进程vi创建的文件a的有效用户。有效组也是同理。为什么我们要定义有效用户和有效组呢?这是因为当用户(假设是test)启动一个特定进程时,有可能获得其他用户(比如root)的文件系统权限!因此,我们把启动进程的用户称为该进程的真实用户。不过,在大多数情况下,有效的用户id和真实的用户id是等同的。下面我们通过本例查看的文件/usr/bin/passwd来解释。众所周知,passwd命令通过修改/etc/passwd文件来更改系统用户密码和相应信息,但是我们使用ls查看/etc/passwd文件,得到的信息如下:
root@x-force:~# ls -l /etc/passwd
-rw-r--r-- 1 root root 1399 2005-06-10 17:57 /etc/passwd
这说明,passwd文件只允许root用户进行写操作,但是,用户test更改密码的时候明明就更改了/etc/passwd这个文件的说,这不是和文件权限矛盾了么?其实并没有。用户test在使用命令passwd更改密码的时候,进程passwd实际获得了root用户的权限,正因为如此,该进程才可以更改/etc/passwd这个只对root用户开放写权限的文件。联系我们前面讲的,如果passwd命令被任意非root用户使用(如用户test),passwd进程实际上获得了root用户的权限,所以passwd进程的有效用户是root,而真实用户则是使用passwd命令的用户(用户test)。
到这里,我们可以来谈/usr/bin/passwd权限位里面's'的定义了。实际上这一位叫做SUID位,它首先表明该文件可执行,同时,其他用户在执行该文件的时候就具有该文件所有者的文件操作权限。所以,用户test在执行passwd命令的时候由于passwd命令文件设置了SUID,才具有了root权限,不然test用户是无法更改/etc/passwd文件的。
另外还有些时候,用户组权限位也会出现字母's',如:-rwxrwsr- - ,和SUID道理一样,出现在用户组这一组权限位中的s称为SGID位,如果设置了这一位,则用户执行该文件所得进程的有效组为该文件的所属组,而不是启动该进程的用户的组。(你也可以自己定义出有效组和真实组的概念了吧。)
最后,我们把9位权限位逻辑化,并初步探讨文件在建立的时候是如何定义出相应权限的。
通过使用ls命令查看Linux系统中的文件,我们可以轻易判断出该文件的权限分配,这是因为权限位使用了各种字母的缩写。但是计算机明白的只是0101的二进制数制,它是如何将二进制流组合成相应权限的呢?
实际上文件的权限可以由八进制值表示(当然,八进制值是由二进制转换得来的),我们根据下表来说明具体的含义:(注:八进制值的第一位恒为零,代表此数为八进制。)
八进制值 含义
O4OO 拥有者可读
O2OO 拥有者可写
O1OO 拥有者可执行
OO4O 同组用户可读
OO2O 同组用户可写
OO10 同组用户可执行
OOO4 其他用户可读
OOO2 其他用户可写
OOO1 其他用户可执行
从表中可以看出,如果想获得某中权限,只需要选出相应的八进制值进行相加即可。比如我们把rw-rw-rw-这样的权限组合转换为八进制值:首先拥有者的权限使可读可写,所以取出0400和0200进行叠加,得到八进制数0600;再来看同组用户权限,还是可读可写,于是取出0040和0020叠加,得到八进制数0060;最后来看其他用户的权限,仍是可读可写,于是取出0004和0002叠加,得到八进制数0006。最后,把三组八进制数叠加起来,得到权限组合rw-rw-rw-的八进制表示:0666,这个数就代表了对应文件的权限即是拥有者可读可写、同组用户可读可写、其他用户可读可写。是不是很简单呢?
有了这个基础,我们可以开始解释下面这个问题了:使用touch命令建立文件test之后,为什么test的权限正好是rw-r- -r- -而不是其他?要解释这个问题,需要简单了解“系统调用”的含义。
Linux操作系统在它的内核中提供了一组面向用户的接口,这些接口下面即是所谓的操作原语,也是系统最底层的函数库,系统调用实际上即是调用了操作原语,这和普通的库函数调用没什么区别。而我们使用的命令如mkdir、vi、touch等都直接或间接的进行了系统调用,所以当我们使用mkdir命令建立一个新的目录时,实际上mkdir是调用了操作原语creat完成此任务的。而creat这个原语(可以理解为函数吧)包含了一系列参数,其中有一项参数“mode”,该参数为一组八进制数,也就是初始化了所建目录的相应权限。同样,我们在使用vi命令新编辑一个文件时,vi调用了操作原语open ,open同样包含了参数“mode”,这样,使用vi打开一个新文件时,实际上一开使已经给此文件附上相应的权限了。
不知道看到这里你是豁然开朗了还是越来越迷糊了 不过我还要试着讲最后的一个东东-----umask,掩码。
我们在Linux系统中经常运行一些网络服务项目,如http 、ftp等等,我们如果查看这些服务项目的配置文件时会发现有的配置项如下:(这里以我的操作系统中的proftpd的配置文件为例)
# Umask 022 is a good standard umask to prevent new files and dirs
# (second parm) from being group and world writable.
Umask 022
我们知道,ftp服务器需要给特定用户特定权限,比如我的ftp目录下有一个upload的子目录,该目录的拥有者和拥有组分别是up:up ,相应权限是rwxr-xr- x ,这样其他用户可以进入这个目录,并且,up用户可以在该目录中创建新文件。那么,up用户创建的文件会聚有什么权限呢?通过上面对创建文件的系统调用的讲解,应该知道up用户创建的文件的权限是由创建操作原语里的mode参数决定的,但是,这样我们并不能保证该文件的安全性。比如创建操作原语里的mode参数被改成0777,也就是说,所有用户都拥有新创建文件的满权限!这当然不行。此时,为了验证和保证我们系统的安全性,umask就发挥其作用了。简单的说,umask实际上起到监察和修复新创建文件权限的作用,将设置好的umask值按位取反,并与新创建文件的权限的八进制数右对齐,逻辑与运算,得到的数才是真正的创建的文件的权限。复杂么?拿上面例子来说,我们知道我的ftp服务器设置的umask为022,假设用户up在子目录upload里建立的所有文件都被系统初始化为满权限(对应八进制数0777),每当up建立一个新文件时,umask便会和初始化的权限(0777)进行如下运算:首先,都写成二进制,umask:000 010 010 ;0777:111 111 111。然后umask取反,得到:111 101 101。最后,umask的取反和0777相与,得到新的二进制数:111 101 101,写成八进制数:0755。所以,实际上新创建的文件的最后权限就为rwxr-xr-x了。
另外,在某些配置文件里不是umask,而是mask,如samba的配置文件。其实道理都一样,只不过mask的值换算成二进制后不用取反就是了。
好了,不知道这篇短文是否让你对文件权限有了更深一层的了解。最后我想说明的是,由于自己的水平尚且有限,所以难免文章中有些内容会有错误,希望大家能够指出!
参考资料:
Evi Nemeth ,Garth Snyder And Trent R.Hein . Linux Administration Handbook . TELECOMMUNICATIONS PRESS.2003
Keith Haviland ,Dina Gray,Ben Salama . UNIX System Programming Second Edition . Publishing House of Electronics Industry.2003 |
|