基本认知
什么叫做权限
当我们去访问资源的时候,权限就是限制我们能还是不能的问题。
为什么要有权限
Linux是一个多用户操作系统,一台机器同时可能会有多个人来进行登录访问,最常见的就是普通用户和root,如果没有权限,例如普通用户可以访问root里的文件,那万一出了错,责任归谁?因此权限本质是为了更好的进行用户管理。
权限=人+文件属性
权限是针对特定群体(与人有关)的,就比如你想进某个大学,但是你并不是里边的学生,那就无权限进去,但你如果是里边的学生就有权限进去,Linux里的特定群体就是普通用户和root。除了人,权限还得需要目标主体天然具备对应的属性才能访问,仔细想想,你能去腾讯视频里敲代码吗?即使腾讯视频有权限让你进去,但它根本没有对应写代码的属性。反观Linux,Linux下一切皆文件,则对Linux的任何操作都避不开文件,文件就是Linux里权限的目标主体,它的属性就是可读(r),可写(w),可执行(x)。
权限
Linux用户的问题
Linux里有两类用户,一个是普通用户,一个是超级用户root。其中root在百分之99的情况下不受权限约束,属于Linux系统中的特权级别,普通用户受权限约束。root和普通用户之间可以进行账号切换,root切换到普通账号,su 账号名 ,就切换到了对应名字的普通用户(不需要密码)。普通账号切换到root,su root或者su或者su - (为什么只要su,因为Linux系统里只有一个root账号),并且还要输入root的密码。 普通账号之间切换,su 账户名,并且还要输入对方的密码。ctrl+d,退到上一个登录的用户账号下。注:su是只进行账号切换,不改变当前的工作路径(家目录还是上一个账号的),su -是让目标用户已重新登录的方式进行账号切换(家目录变成了当前账号的)。每一个人安稳用自己的账号就行。(上述这种情况是普通账号跟root账号是同一个人)
现在我们基本知道了root和普通账号之间是存在着一定的权限差距的,那如果说普通账号想做提高权限的事情,就比如说在Linux系统里安装软件,需要拷贝到指定的目录下,操作系统不让普通账号进行拷贝,那难道说安装个软件还需要请root账号亲自来做吗?当然不是,如果普通账号有成百上千个,那root一个个去搞不得累死。因此,Linux系统里有个指令叫sudo,可以让普通账号进行指令短暂提权的。第一次用sudo需要输入一次密码,之后会有十几分钟用sudo的时候不需要。(上述这种情况是普通账号跟root账号不是同一个人)
关于上述sudo肯定有人有疑惑说,我使用的时候为什么要求输入我当前自己的密码,当然可能现在大家根本就用不了sudo,这个下边说,现在先讨论为什么输入自己账号的密码,如果输入自己账号的密码怎么感觉root账号形同虚设,普通账号不就想提权就提权了吗?先明确一个点,这里肯定是不能输入root的密码的,因为root的密码不可能给所有人都知道吧,另外,普通用户默认是执行不了sudo的(虚拟机除外),这也就不存在root账号形同虚设之说。
如何使用sudo?首先在用sudo的时候,系统会弹出来一句话,叫不在sudoers文件里,那这个文件是什么呢?sudoers是root超级管理员的配置文件,任何人无法直接查看这个配置文件,只有root才可以去访问修改,这个文件相当于是一个白名单,白名单的意思就是在这个名单里的用户都不用做身份验证,像比如你是校长的儿子,进学校的时候,保安问都不问直接就让你进去了,但是换做其他学生,保安会叫说要看看学生证。不在白名单里的用户都默认是不许用sudo的,Linux系统使用这种名单机制去限制普通用户能否提权,并且如果有人恶意去删除修改文件,也可以直接去白名单里查找,缩小了查找范围。总结一下,一个普通用户能用sudo,一定是经过root管理员认证过的,因为必须要将其添加到白名单里才能使用,而白名单只能由root进行访问修改,这也就解释了为什么普通账号用sudo的时候只要输入自己的密码就可以进行短暂提权了。
Linux角色的问题
权限是依附于角色的,就像你充了腾讯视频的会员,可以看里边的VIP视频,是因为你这个人还是因为你是会员?Linux里常见的有三种角色,拥有者角色(文件的创建者),所属组角色(文件属于哪个组),other角色(不是拥有者不是所属组就是other,系统里没有为它专门设置一栏属性)。
Linux里的用户跟角色有什么关系呢?角色是需要人来扮演的,比如说用户有一个root账号,而root在文件属性里的角色为拥有者/所属组。就像一个人叫张三,他的角色是校长,明天换李四当校长,角色还是校长。角色和用户是互补的关系,角色一直在那,但人可以变。
所属组是什么?为什么要有所属组?在日常开发的过程中,通常是一个小组一起开发,肯定是共用文件的,这时候它们用到的就是组级别权限,简单理解就是拥有者创建的文件不许other看但允许一个小组里的人看,所属组就是对文件权限进行局部范围的组级别管理。
文件权限属性的问题
文件的权限主要分为只读(r),只写(w),可执行(x)三种。
了解了对应的意思之后就可以去表达一个文件的权限了,以文件dst.txt为例,该文件的拥有者为root,所属组为root(注意所属组可以只有一个人),该文件所对应的拥有者的权限为可读可写不可执行,所属组的权限为只读不可写不可执行,other的权限为只读不可写不可执行。
权限的指令操作
修改文件属性
chmod可以修改文件的权限。假设现在要操作的文件是text.txt。u表示拥有者,g表示所属者,o表示other,-表示去掉某个权限,+表示加上某个权限,a表示all,对所有角色的权限一起修改。

补充:对于超级用户来说,上文说过,root账号可以用su随意切换到普通账号不用输密码。对于文件权限来说,root也不受文件权限的限制,文件权限只对普通账号有限制。假设现在我登录了一个叫做xxc的普通账号并且创建了一个叫text.txt的文件,我还将这个文件对于other的权限chmod成了不可读不可写不可执行,另外,此时root对于text.txt来说是other,但由于它的超级用户,不受文件权限的限制,依旧可读可写可执行。
细节1:对于一个文件来说,只有该文件的拥有者才能使用chmod去修改任意角色的权限。 现在假设xxc是这个文件的拥有者,他将自己的权限改成了不可读不可写不可执行(至于这种情况对应的场景,大模型一搜就知道了),但是他又是文件的所属组,所属组的权限是可读可写不可执行,那此时xxc还是否能读写这个文件呢?实践可知,不行。另外通过这个也可以知道,当没有对应权限的时候系统会打印Permission denied。
原因就是**用户访问文件的时候,确定自己相对于文件的身份角色,只会验证一次。**换句话说,权限只会验证一次。意思就是现在我登录的这个账号名叫xxc,用这个账号创建了一个text.txt文件,也就是xxc创建了一个text.txt文件,他是文件的创建者,这个事比xxc是文件的所属组先确定下来(文件权限所对应的角色从左往右依次确定,这里指的从左往右看的是ll打印出来的那个顺序),因此,系统不会再去验证xxc的身份,就导致xxc对于该文件的权限就是不可读不可写不可执行。
那么如何验证这个事呢?其实上边已经间接验证了,因为当把xxc的权限修改成---之后再去echo或者cat就Permission denied了,这也就说明身份只验证了一次,不然不就可以echo和cat吗。现在再直接验证一下,我要保证文件的拥有者和文件的所属组不是同一个人,这样就能知道当xxc不是拥有者的时候是否能匹配上所属组的可读可写权限。由下图可知,当我改完拥有者之后,xxc的角色就从左往右匹配,先匹配看看是不是拥有者,不是,拥有者现在是root,继续往右匹配到了所属组,是的,并且text.txt这个文件的所属组角色具有可读可修改的权限,因此xxc此时就可读可修改了,这也就直接验证了上边的结论。
细节2:关于文件的可执行权限,chmod可以修改文件的权限,那是不是就是说如果将文件的权限修改成了可执行就代表这个文件可以执行了呢?不是的,文件要被执行要满足两个条件,一个是该文件本身就是一个可执行的文件,第二个就是文件本身具有可执行权限。所以,有x权限只是其中一方面而已。给x权限,不是能让你从不可执行的文件变成可执行的文件,而是这个文件本来就可执行,当你给x权限的时候,你想执行,OS允许你执行。
谈完了上边的两个细节之后,接下来谈一谈修改文件属性的第二个方案,叫做8进制方案。什么意思?

修改人
上边修改的一切都归结为在修改文件的属性,现在该谈谈人了,因为权限=人+文件属性。已经过说,那9个字母每三个为一组,分别代表的是拥有者权限,所属组权限,other权限,另外,ll的时候两个账号名分别表示的是拥有者和所属组。我们是没有办法去修改它们的,举个例子,没法将第一组的三个字母本来表示的是拥有者权限,现在将它的意思改成所属组的权限,其他的同理,但是我们可以修改拥有者和所属组,举个例子,现在拥有者为xxc,将其改成root。也就是说每个位置对应的角色不可以变,但是该角色对应的人可以变。
以root账号修改人为例,因为root账号权限最大。chown改变拥有者角色对应的人,chgrp改变所属组角色对应的人,chown还可以将拥有者和所属组角色对应的人一起改变了。注意没有指令去修改other,因为不是拥有者不是所属组的就是other,改变拥有者和所属组的时候就是在改变other。
上文说过,文件的拥有者可以修改文件的权限,那我现在text.txt文件的拥有者为xxc,他是否能修改文件的拥有者或者所属组角色对应的人呢?答案是不行的,拥有者只能修改角色之于文件的权限(就是那3个为一组的9个字母)。拥有者在修改文件权限的时候不会影响他人,因为这个文件修改了权限之后还是拥有者自己的,但是当拥有者想去修改拥有者或者所属组的人的时候,你把东西给别人是不是要征得别人的同意?但在Linux里没法去征得别人的同意,这个时候就让超级用户去强制给,或者sudo提高权限去给,就算出了错,那也能断定一定是在白名单里,好查。
关于文件类型的补充
Linux的文件类型里不以文件后缀作为区分。
-:普通文件,源代码,文本,动静态库,可执行
d:目录///////////////////////////////////////////////////////////////////////////////
l:链接文件
p:管道文件
c:字符文件(字符设备)(典型的是显示器,键盘,按照顺序IO,不支持随机读写,以字节为单位进行读写)样例:当用printf在屏幕上打印1234的时候,其实是按字符打印的,而不是以整体1234这个整数打印的。scanf,cin,cout都是如此,因为显示器是字符设备。
b:块设备文件(典型的就是磁盘,其支持随机读写(以块为单位,一般是4KB),速度快)
三个子问题
问题1:目录权限问题:如果要进入一个目录需要什么权限。
目录也有对应的rwx三种权限。(注意以下的rwx说的都是对目录的影响,但是不影响对目录里文件的操作,对文件的操作需要的是文件的权限,就比如向文件写入,只要文件特定的角色有w权限就可以)
r:表示用户是否有权力查看目录底下的所有文件。
w:决定特定用户是否有权力在目录下增加删除文件和修改文件名。
x:决定了用户角色是否可以进入目录
关于目录的rwx之所以是那样的可以暂时先这么理解:Linux下一切皆文件,因此目录也是一个文件,文件=文件内容+文件属性,对于目录来说,它的内容是目录下所有文件的属性,在目录里新建文件就相当于往目录里增加了新建文件的属性,没有w权限这是不允许的。读权限也同理,目录也是文件,它的内容是目录下所有文件的属性,没有r权限就读取不了文件的内容,也就是目录下所有文件的属性。(为什么说暂时这么理解是因为这个表述还有点问题,因为目录没有w权限,不能修改目录里文件的文件名但是可以修改文件的属性。)
问题2:为什么我们新建的目录和起始文件是我们看到的样子。
对于普通文件,起始权限是从666开始的,对于目录文件,起始权限是从777开始的,中间的差别就是差了x权限,对于大部分普通文件来说都只是普通的文本文件,不需要被执行,因此x权限就默认没有了,而对于目录来说,创建目录就是为了访问,因此x权限是默认带上的。但是我们实际看到的是664和775,这是为什么呢?因为在Linux系统中,为了对权限进行细粒度(更精细的做权限管理)控制,因为不想让other有太大的权限,有个叫Linux权限掩码的东西,umask指令可以查看Linux系统的权限掩码,第1位的0先不管,后3位002是权限掩码。上文说的666,777叫起始权限,权限掩码的意思就是凡是在权限掩码中出现的权限都应该从起始权限里去掉。
新建文件/目录的最终权限(就是我们肉眼实际看到的664,775) = 起始权限去掉权限掩码中出现的权限
权限掩码是8进制的,也就是002变成2进制是000 000 010,新建文件的起始权限是666,也就是110 110 110,权限掩码里对应other的权限是010,其中w权限出现在了权限掩码里,所以就将起始权限里对应other的w权限去掉,由1变成0,因此新建文件的最终权限为110 110 100,即为664。(新建目录同理)。
(误区:公式里所说的去掉不是指的减法,真正计算最终权限的方式是:最终权限 = (起始权限) & (~权限掩码),解释一下1&1==1,1&0==0,0&1==0,0&0==0,也就是说,1跟任何二进制数&之后得到的还是原来的二进制数字,说白了就是保留原始位数字不变,0跟任何二进制数&之后会将原来的二进制数字清0。之前又说过,在权限掩码中出现的权限(为1的位)要在起始权限中去掉(清0),因此要先~在&。
实践:那我们是不是可以通过修改权限掩码的方式去修改最终权限?umask 3位8进制数字 ,例如umask 000,则将权限掩码修改成了000。注意这只是临时修改权限掩码,关掉重新登录一下之后,权限掩码就会恢复成系统默认的了,而且不同系统下默认的权限掩码可能不一样,这都很正常。
问题3:如果我们新建的一个文件是不可读不可写不可执行的,可以删掉它吗?粘滞位问题。
假设现在在你账号的一个家目录里边有一个root账号创建的文件,这个文件是---的,对于这个文件来说,你是other,然后你看到这个文件是---的,你就把它删了,并且还删成功了,你觉得合理吗?其实是合理的,因为我要删除文件,需要的不是文件的权限,而是文件所属目录的w权限,只要文件所属的目录有w权限就可以删除文件。还有一个比较好理解的角度就是,当前这个目录是我的,假设账号名叫xxc,而root账号进入到xxc的目录里边去新建了文件还设置成---,虽然xxc确实---了,但是当前这个文件所属目录是xxc的,xxc有删除这个文件的权力。
结论:指定目录下,一个其他人新建的文件(即便是root),不让rw,但是可能我们普通用户可以删掉。这个可以删掉的本质是这个目录就是这个普通用户的(就是这个目录的拥有者是这个普通用户,因为拥有者可以修改目录的权限,只要目录有w权限就可以删除里边的文件)。
如果我们今天想让多用户之间共享文件怎么办?首先要明确这个共享文件一定不可能出现在某个任意用户的家目录下,因为多个普通用户之间是无法进入对方的家目录以及家目录的子目录的,因为家目录默认是对所属组和other是---的,并且即使是root可以进入普通用户的家目录,普通用户也有删除root所创建的文件的权力。(*是通配符,指代任意字符,-d表示只显示目录本身,不显示目录里的文件),既然不能在家目录里共享文件,那就只能去系统级别的路径下了,也就是根目录/,sudo一下去根目录里新建一个目录,将文件写在根目录里边去共享。
假设下图的shared目录里的name.txt就是两个用户之间共享的文件,此时有第3个用户进入了这个目录,因为这个目录对于other是有x权限的并且还有w权限,所以这第3个用户把name.txt删除了,合理吗?从技术角度是合理的,因为只要目录有对应的权限就可以做到,但我现在的场景是shared是我们共享的目录,里边文件的权限由文件的拥有者去设定别人可不可读写,这都没有问题,不过我不想随便哪个人都可以来删除我这个文件,跟我共享可以,你可以r和w,但不想你删除,肯定有人会想,此时把shared目录的w去掉不就可以了吗?但是去掉之后我自己都不能删除我自己的文件了!

因此对于这种场景,在共享目录里每个用户自己创建的文件只能自己删除,别人对这个文件只能r或者w或者x或者---,此时就需要一个权限去凌驾于w权限之上,称为粘滞位,t。(前提条件肯定这个目录本身对于你这个角色有w权限)(t就表示粘滞位这个权限,然后写指令的时候不用去指定u,g或者o),加完之后会发现shared目录原来对于other的x权限的位置变成了t这种权限。


总结一下,粘滞位是给other设置的一种权限管理级别:在带有粘滞位t的目录下,每个人新建文件,删除的时候只能自己删自己的,不能因为目录有w权限而删除别人的文件,粘滞位通常用来做文件共享的场景。只有三类人可以在带有粘滞位的目录下删除文件,超级管理员,该目录的所有者,该文件的所有者(说白了就是自己删自己的)。
补充:Linux系统里的根目录/下有一个目录tmp,其本身就是共享的目录,并且设有粘滞位,这个目录下通常保存系统里各个用户所形成的临时文件、临时数据。