一文读懂Linux文件权限控制相关

文件权限基本概念

  • Linux一般将文件权限身份分为三种:ownergroupothers
  • Linux系统默认情况下所有账号信息(包括root)都记录在/etc/passwd文件中。个人密码则是记录在/etc/shadow文件下。群组名称记录在/etc/group

Linux文件属性

  • 切换至root账户命令:su root
  • 退出root账户命令:exit
  • 查看文件属性命令:ls -al或者ll

https://img-blog.csdnimg.cn/img_convert/87df422e0d5750f87a3792a9cfcfc7ed.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=140&id=ube75acda&margin=[object Object]&name=image.png&originHeight=175&originWidth=602&originalType=binary&ratio=1&rotation=0&showTitle=false&size=19056&status=done&style=none&taskId=u7cf57ff9-0335-4e7b-ba09-fd4673bd1f2&title=&width=481.6

第1列为权限
第2列为链接,表示有多少文件名链接到此节点(i-node)
第3列为owner
第4列为group
第5列为文件大小
弟6,7,8列为文件修改日期
第9列为文件名

权限列解读

  1. 权限列第一个字符表示文件类型
  • 当为d则是目录
  • 当为-则是文件
  • 若是l则表示为链接文件
  • 若是b则表示为设备文件里面的可供储存的周边设备(可随机存取设备);
  • 若是c则表示为设备文件里面的序列埠设备,例如键盘、鼠标(一次性读取设备)。
  1. 权限列后面每3位为一组,且都是rwx组合,r代表可读,w代表可写,x表达可执行。 第一组代表owner的权限,第二组代表group的权限,第三组代表others的权限。

例如:-rw-r--r-- 1 root root 6 May 6 10:38 test.txt

  • 第1位为-,表示test.txt为一个文件
  • 第2-4位为rw-,表示test.txt的owner对该文件有读写权限,但是没有执行权限
  • 第5-7位为r--,表示test.txt的group成员对该文件只有读权限,没有写和执行权限
  • 第8-10位为r--,表示test.txt的除去owner和group之外的用户对该文件只有读权限,没有写和执行权限

修改文件权限

  1. 改变文件所属群组:chgrp [-R] [groupname] [dirname/filename]
  • -R表示递归修改所属群组,可以在修改目录所属群组时使用,递归将目录下所有文件的所属群组修改。

https://img-blog.csdnimg.cn/img_convert/8d027d50bf7ad4db9bf88c9235a477af.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=ue188f261&margin=[object Object]&name=image.png&originHeight=312&originWidth=627&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38510&status=done&style=none&taskId=u0fd23cd7-a4e3-4f88-8673-8600ce80c3a&title=&width=501.6

groupname必须是在/etc/group文件中存在的群组名,否则会报错

  1. 改变文件所有者:chown [-R] [ownername] [dirname/filename]

https://img-blog.csdnimg.cn/img_convert/5669b538424f833882d73f19370cf46f.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=244&id=ud8554789&margin=[object Object]&name=image.png&originHeight=305&originWidth=622&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38311&status=done&style=none&taskId=u6eca00e3-8ea9-498a-9e2a-8ec3716be4f&title=&width=497.6

  • 还可以直接同时修改owner和group:chown [-R] [ownername]:[groupname] [dirname/filename]

https://img-blog.csdnimg.cn/img_convert/01f0088776bdb03bb19478c2641d5dc6.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=ud1ec9da9&margin=[object Object]&name=image.png&originHeight=312&originWidth=618&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38268&status=done&style=none&taskId=u6f635b7e-d19e-4836-9c72-1264d4e5ffc&title=&width=494.4

ownername必须在/etc/passwd文件中存在的用户名,否则会报错

  1. 修改文件权限:chmod [-R] xyz [dirname/filename]
  • Linux系统中给权限分别分配了权值:r -> 4w -> 2x -> 1。上述test.txt文件中owner权限为rw-,其权值为6,group和others权限都为r--,权值都为4,故用权值的形式表达test.txt文件为644
  • Linux系统分别用ugo符号来代表owner、group、others
  • 通过权值的方式直接修改文件权限:

https://img-blog.csdnimg.cn/img_convert/11fadff0da10d77e460ec84c604308d5.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=u83192ced&margin=[object Object]&name=image.png&originHeight=312&originWidth=617&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38628&status=done&style=none&taskId=ub264f433-e158-4ad2-a219-163f2f81b8a&title=&width=493.6

上述用chmod 777 test.txt之后可以看到test.txt的文件权限变为了-rwxrwxrwx

  • 通过符号来+-给对应用户添加、删除权限

https://img-blog.csdnimg.cn/img_convert/400e2dd4ac135d6215456cba3b18a8ae.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=257&id=ua0d7db6d&margin=[object Object]&name=image.png&originHeight=321&originWidth=642&originalType=binary&ratio=1&rotation=0&showTitle=false&size=47090&status=done&style=none&taskId=u75328605-a124-4186-9778-e2b07bc26bc&title=&width=513.6

  • 使用chmod u=rw,go=rw test.txt后,可以看到test.txt文件权限变为-rw-rw-rw-,说明可以直接使用u|g|o = r|w|x的方式直接修改文件权限
  • 使用chmod u+x,go-w test.txt后,可以看到test.txt文件权限变为-rwxr--r--,说明可以直接使用u|g|o +|- r|w|x的方式直接给指定身份添加或删除文件权限
  • 使用chomod a-x test.txt后,可以看到test.txt文件权限变为-rw-r--r--,这里a代表的是所有用户的意思,所以直接将owner、group、others的权限都删去了x权限。

目录与文件权限意义

文件类型 内容 r w x
文件 详细数据data 读取文件内容 修改文件内容 执行文件
目录 文件名 读到文件名 修改文件名,以及目录中内容 进入目录
  • 只有对目录有执行权限,才可以进入目录

https://img-blog.csdnimg.cn/img_convert/6c864b2ff2ef590858b7af6a242fd432.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=230&id=u89a2e397&margin=[object Object]&name=image.png&originHeight=287&originWidth=662&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27901&status=done&style=none&taskId=u03d679e4-8b90-4803-babb-c2b49f47600&title=&width=529.6

  • 如果对目录没有r权限,则即使有x权限进入了目录,使用ls命令也是会报permission deny错误

https://img-blog.csdnimg.cn/img_convert/58c45c1ca39506e30965a58faeef7ef4.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=uc1945c47&margin=[object Object]&name=image.png&originHeight=313&originWidth=652&originalType=binary&ratio=1&rotation=0&showTitle=false&size=29877&status=done&style=none&taskId=u58fc4823-f2b3-4b80-a69a-ab8bb54d9f5&title=&width=521.6

上图中,我们为zean用户,对test目录权限为--x,所以执行cd test成功,但是在目录中执行ls失败

  • 若用户对目录没有w权限,则无法在目录中添加、删除文件

https://img-blog.csdnimg.cn/img_convert/306c0fa0b2fb54b25326da4336af04b9.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=314&id=u4e39b276&margin=[object Object]&name=image.png&originHeight=393&originWidth=670&originalType=binary&ratio=1&rotation=0&showTitle=false&size=37802&status=done&style=none&taskId=u45aae9fa-9f49-4233-816b-50b434ab0de&title=&width=536

上图中为zean用户,对test目录权限为r-x,没有写权限,所以执行cd testls成功,但是在用echo hello > b.txt创建b.txt文件时失败,rm a.txt删除a.txt时失败。
在目录中添加文件和删除文件,需要的是wx权限

https://img-blog.csdnimg.cn/img_convert/d8944f808c6b2aa925af5e394278d425.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=341&id=ua8f5f6c3&margin=[object Object]&name=image.png&originHeight=426&originWidth=700&originalType=binary&ratio=1&rotation=0&showTitle=false&size=36005&status=done&style=none&taskId=u56952ea8-a7b5-4edd-a422-f7d46d30985&title=&width=560

将test权限设置为777之后,zean用户就可以在目录中添加或删除文件

文件的默认权限

  • 可以通过umask命令查看文件的默认权限,文件默认权限的意思是:当前用户创建文件时,文件拥有的权限。

https://img-blog.csdnimg.cn/img_convert/f6d1364ee0faa57b6aa28306f5dca5c2.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=138&id=u5b52dec9&margin=[object Object]&name=image.png&originHeight=172&originWidth=442&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10041&status=done&style=none&taskId=u29e1656f-e1f4-436d-aea4-f26d2395667&title=&width=353.6

  • 输入umask命令后,会输出4个数字,第一个数字是给特殊权限用的,后面三个数字分别是owner、group、others对应的权限。且是以减分的方式,数字0代表权值7,即7-7=0;数字2代表权值5,即7-5=2
  • 通过上图可知,笔者使用的系统中root用户创建文件的默认权限权值为755,即rwxr-xr-x;zean普通用户创建文件的默认权限权值为775,即rwxrwxr-x

https://img-blog.csdnimg.cn/img_convert/45e648d82108267418fb3172a867ee29.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=126&id=u0467978d&margin=[object Object]&name=image.png&originHeight=157&originWidth=635&originalType=binary&ratio=1&rotation=0&showTitle=false&size=19038&status=done&style=none&taskId=u5739c62d-362d-4d3b-bba6-ff89d085428&title=&width=508
https://img-blog.csdnimg.cn/img_convert/3df22c2f71c60d4580f1d3a56b7570ba.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=170&id=u63b3a2fa&margin=[object Object]&name=image.png&originHeight=212&originWidth=596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=18654&status=done&style=none&taskId=u31b54cf9-3fd4-420f-b1e6-76025dbe54e&title=&width=476.8

可以看到,通过root用户创建的目录,权限为drwxr-xr-x
通过zean普通用户创建的目录,权限为drwxrwxr-x

  • 可以通过umask -S打印符号形式的默认权限

https://img-blog.csdnimg.cn/img_convert/71da2012cbfde794107d156ac4cdd091.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=78&id=u6030f6ed&margin=[object Object]&name=image.png&originHeight=98&originWidth=447&originalType=binary&ratio=1&rotation=0&showTitle=false&size=4175&status=done&style=none&taskId=ufd93fe07-ca3f-40d4-8d7f-a4830d0bfac&title=&width=357.6

  • 可以通过umask xyz修改文件默认权限

https://img-blog.csdnimg.cn/img_convert/02af656e84e401b424df4c3047be21bb.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=130&id=ud2ad8052&margin=[object Object]&name=image.png&originHeight=162&originWidth=562&originalType=binary&ratio=1&rotation=0&showTitle=false&size=15557&status=done&style=none&taskId=u4ea2c250-86e2-4d84-b510-78ad0c5e33f&title=&width=449.6

文件的隐藏属性

  • 文件除了正常的读、写、执行权限,还有一些特殊的隐藏属性,对文件进行更加细粒度的权限控制
  • chattr指令只能在Ext2/Ext3/Ext4的 Linux 传统文件系统上面完整生效, 其他的文件系统可能 就无法完整的支持这个指令了,例如 xfs 仅支持部份参数而已
  • 可以通过chattr [+-=][ASacdistu] [dirname\filename]来设置隐藏属性。其中+表示添加,-表示删除,=表示直接设置,后面的[ASacdistu]是想要设置的属性
  • A :设置该属性后,当你有存取此文件(或目录)时,他的存取时间 atime将不会被修改, 可避免 I/O 较慢的机器过度的存取磁盘。(目前建议使用文件系统挂载参数处理这个项目) 可以从下图看到,在添加A属性后,使用cat a.txt读取文件,并不会修改它的存取时间。移除A属性后,再使用cat a.txt读取文件,发现存取时间发生了改变。

https://img-blog.csdnimg.cn/img_convert/459f9e79858e3105e21df786366b11c5.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=276&id=u2ecc1018&margin=[object Object]&name=image.png&originHeight=345&originWidth=656&originalType=binary&ratio=1&rotation=0&showTitle=false&size=41045&status=done&style=none&taskId=u924b186b-d349-432c-a555-0ab3b5c6f03&title=&width=524.8

  • S :一般文件是非同步写入磁盘的,加上 S 这个属性后, 当你进行任何文件的修改,修改会“同步”写入磁盘中。
  • a :当设置 a 之后,这个文件将只能增加数据,而不能删除也不能修改数据,只有root 才能设置这属性 。从下图看出,添加a属性后,使用echo hello > a.txt覆盖文件内容失败。但是使用echo hello >> a.txt在文件末尾添加内容添加成功。在移除a属性后,使用echo hello > a.txt覆盖文件内容成功

https://img-blog.csdnimg.cn/img_convert/d3b646819b4cc6c52b3f7a8eb5fe8554.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=188&id=u7cdc7258&margin=[object Object]&name=image.png&originHeight=235&originWidth=585&originalType=binary&ratio=1&rotation=0&showTitle=false&size=29175&status=done&style=none&taskId=u05f68c31-4d32-4e5c-b0f2-89e8afdcefc&title=&width=468

  • c :这个属性设置之后,将会自动的将此文件“压缩”,在读取的时候将会自动解压缩, 但是在储存的时候,将会先进行压缩后再储存
  • d :当 dump 程序被执行的时候,设置 d 属性的文件(或目录)不会被 dump 备份
  • i :设置该属性后,可以让该文件“不能被删除、改名、设置链接也无法写入或新增数据!”只有 root 能设置此属性 。下图中,给a.txt添加i属性后,执行echo hello > a.txtecho hello >> a.txtrm a.txt均失败,即无法修改、添加、删除文件。移除i属性后,使用echo hello > a.txt成功。

https://img-blog.csdnimg.cn/img_convert/0e0931ecc6b3b6c91ad846ee25ebcd2c.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=210&id=ub334f696&margin=[object Object]&name=image.png&originHeight=263&originWidth=747&originalType=binary&ratio=1&rotation=0&showTitle=false&size=36309&status=done&style=none&taskId=uac766a2f-36e5-426c-867d-c72b0b18004&title=&width=597.6

  • s :当文件设置了 s 属性后,如果这个文件被删除,他将会被完全的移除出这个硬盘空间, 所以如果误删了,无法恢复
  • u :与 s 相反的,当使用 u 来设置文件时,如果该文件被删除了,则数据内容其实还存在磁盘中, 故有办法恢复

注意:属性设置常见的是 a 与 i 的设置值,而且很多设置值必须要身为 root 才能设置

  • 可以通过lsattr [-adR] [dirname\filename]来查看隐藏属性
    • -a:将隐藏文件的属性也显示出俩
    • -d:如果接的是目录,仅列出目录本身的属性而非目录内的文件名
    • -R:连同子目录的属性也一并列出来

https://img-blog.csdnimg.cn/img_convert/e5fc7e1c31fc746c3b486391a38f5668.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=146&id=u796e731f&margin=[object Object]&name=image.png&originHeight=182&originWidth=607&originalType=binary&ratio=1&rotation=0&showTitle=false&size=17549&status=done&style=none&taskId=u01bda8bf-36cb-4f93-b53e-9f6649792c9&title=&width=485.6

文件特殊权限: SUID, SGID, SBIT

Set UID

  • 当s标志出现在文件拥有者owner的x权限上时,例:-rwsr-xr-x,此时称为Set UID,简称为SUID特殊权限。它的限制和功能为:
    • SUID权限仅对二进制程序有效,对shell script和目录无效
    • 执行者对于该程序需要具有x的可执行权限
    • 本权限仅在执行该程序的过程中有效
    • 执行者将具有该程序拥有者(owner)的权限

举例:

  • /etc/shadow文件中存放的是用户密码,权限为rw-r-----,所以只有root用户才可以写。

https://img-blog.csdnimg.cn/img_convert/8ee584928ee1bf4ba600371aa7301a56.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=86&id=u33e25b1c&margin=[object Object]&name=image.png&originHeight=108&originWidth=705&originalType=binary&ratio=1&rotation=0&showTitle=false&size=11752&status=done&style=none&taskId=u3c721db0-2866-41f4-9d08-f079e304890&title=&width=564

  • 但是作为zean这个普通用户来说,应该有权利修改自己的密码。而在linux中修改密码一般用passwd命令。来看看passwd命令对应二进制文件的权限

https://img-blog.csdnimg.cn/img_convert/a550c554b11cbec049dc2add0529f668.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=82&id=u69ca74d4&margin=[object Object]&name=image.png&originHeight=103&originWidth=723&originalType=binary&ratio=1&rotation=0&showTitle=false&size=12941&status=done&style=none&taskId=u84305d46-114e-4167-a2b6-fa3f81f5a23&title=&width=578.4

  • 可以看到/usr/bin/passwd权限为rwsr-xr-x,zean用户对其有执行权限,owner中x标志位位置为s,所以zean在执行passwd命令时,会获得和owner一样的权限,即提权为root。这样,zean普通用户就可以修改自己的密码了。

几个关键点:

  • zean 对于 /usr/bin/passwd 这个程序来说是具有 x 权限的,表示 zean 能执行 passwd
  • passwd 的拥有者是 root 这个帐号;
  • zean 执行 passwd 的过程中,会“暂时”获得 root 的权限;
  • /etc/shadow 就可以被 zean 所执行的 passwd 所修改。

Set GID

  • 当s在文件拥有者owner的x项目为SUID,则s在群组group的x时则称为SGID。功能和限制为:
    • SGID对二进制程序有用,也可以用在目录上
    • 执行者对该程序需具备x权限
    • 执行者在执行过程中获得该程序群组一样的权限
  • 对于二进制文件来说,和SUID功能类似,也是执行至获得该程序群组一样的权限
  • 对于目录来说,设置SGID:
    • 执行用户若对于此目录具有 r 与 x 的权限时,该执行用户能够进入此目录;
    • 执行用户在此目录下的有效群组(effective group)将会变成该目录的群组;
    • 用途:若执行用户在此目录下具有 w 的权限(可以新建文件),则执行用户所创建的新文件的群组与此目录的群组相同。 即新建文件所属群组为effective group这个群组。

Sticky BIT

  • 在others权限上x的位置上为t,功能和限制为:
    • 仅对目录有效
    • 用于当使用者对此目录具有w,x权限,亦具有写入权限时
    • 当使用者在该目录下创建文件或目录时,仅有自己与root有权利删除该文件

https://img-blog.csdnimg.cn/img_convert/d4de28e9030fbd4f41549a03e739ba30.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=242&id=ua43223fb&margin=[object Object]&name=image.png&originHeight=302&originWidth=712&originalType=binary&ratio=1&rotation=0&showTitle=false&size=34102&status=done&style=none&taskId=ua6c1215b-ea40-4e07-adac-d280781532d&title=&width=569.6
可以看到,tmp目录设置了SBIT,使用root用户创建a.txt后,修改a.txt的权限为777,切换到zean用户,执行rm a.txt失败

https://img-blog.csdnimg.cn/img_convert/febe1ac98ebcdc2bab9705b4f31c501e.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=ue31fb205&margin=[object Object]&name=image.png&originHeight=313&originWidth=632&originalType=binary&ratio=1&rotation=0&showTitle=false&size=28929&status=done&style=none&taskId=u47256165-8999-4b47-b9d6-e48e9da3482&title=&width=505.6
可以看到,在没有设置SBIT权限的目录中,创建文件并设置为777权限之后,非创建者也可以删除该文件。

设置特殊权限的方法

  • 原先设置普通权限,使用chmod xyz既可,要设置特殊权限,只需要在这三个数字前面再加上一个数字既可。
  • 其中SUID -> 4SGID -> 2SBIT -> 1

https://img-blog.csdnimg.cn/img_convert/9bd4f3ceaca19cd666291474362f9b7c.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=130&id=u968e0a79&margin=[object Object]&name=image.png&originHeight=162&originWidth=763&originalType=binary&ratio=1&rotation=0&showTitle=false&size=21394&status=done&style=none&taskId=u61397dca-4688-44da-a7b2-58c8cd64852&title=&width=610.4

  • 当s,t为大写时,即为S,T时,代表SUID/SGID/SBIT为空,是无效的

https://img-blog.csdnimg.cn/img_convert/2d877620903e479df07a8f1c752314f6.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=106&id=u28e01674&margin=[object Object]&name=image.png&originHeight=133&originWidth=785&originalType=binary&ratio=1&rotation=0&showTitle=false&size=15464&status=done&style=none&taskId=u2a53976f-da3f-4714-9c2c-672defa9781&title=&width=628

因为所有用户都没有执行权限x,故对其设置SUID/SGID/SBIT是无效的

  • 通过符号设置:

https://img-blog.csdnimg.cn/img_convert/c93f957ccf52e4b797f4656f4374b9b8.png#clientId=u93de3467-ed8b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=166&id=u8687d7f3&margin=[object Object]&name=image.png&originHeight=207&originWidth=682&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27207&status=done&style=none&taskId=u87d80bad-af3a-4acd-945c-dd871b42f8c&title=&width=545.6

文件权限控制相关UNIX编程

文件信息结构stat

  • 在Linux系统中,每个命名文件会有一个stat结构体保存其信息。
struct stat {
  mode_t	st_mode;		// 文件模式,包含权限位和文件类型
  ino_t		st_ino;			// inode节点号
  dev_t		st_dev;			// 设备号
  dev_t		st_rdev;		// 特殊设备号
  nlink_t	st_nlink;		// 链接数
  uid_t		st_uid;			// 文件owner的用户id
  gid_t		st_gid;			// 文件所属群组的群组id
  off_t		st_size;		// 文件大小,以Byte为单位
  time_t	st_atime;		// 文件最近存取时间
  time_t 	st_mtime;		// 文件最近修改时间
  time_t	st_ctime;		// 文件创建时间
  blksize_t  st_blksize;	// 块大小
  blkcnt_t   st_blocks;		// 分配的磁盘块数量
}
  • stats结构体可以通过statfstatlstat函数获得
#include 
//通过文件路径pathname,获得该文件的stat,并将获得的stat结构体存入buf中
int stat(const char* restrict pathname, struct stat* restrict buf);

//通过文件描述符获取文件stat
int fstat(int filedes, struct stat* buf);

//通过文件路径pathname获取stat,但是该文件需是一个符号链接
int lstat(const char* restrict pathname, struct stat* restrict buf);

st_mode(mode_t)权限位相关

mode 说明
S_ISUID
S_ISGID
S_ISVTX
set UID标志
set GID标志
sticky BIT标志
S_IRWXU
S_IRUSR
S_IWUSR
S_IXUSR
owner读、写、执行权限
owner读权限
owner写权限
owner执行权限
S_IRWXG
S_IRGRP
S_IWGRP
S_IXGRP
group读、写、执行权限
group读权限
group写权限
group执行权限
S_IRWXO
S_IROTH
S_IWOTH
S_IXOTH
others读、写、执行权限
others读权限
others写权限
others执行权限
  • 判断st_mode中包含那些权限为可以使用&运算符,例如:当st_mode & S_IRUSR等于1时,说明该文件的owner具有读权限。

进程实际ID、有效ID和保存ID

  • Linux的用户管理机制中,文件权限控制是基于用户id和组id的。当用户需要改变权限的时候,就需要更换用户ID或者组ID。为了实现这种机制,引入了真实ID(real ID)、有效ID(effective ID)以及保存的ID的概念。
实际用户ID
实际组ID
实际上是谁
有效用户ID
有效组ID
附加组ID
用于文件访问权限检查
保存的设置用户ID
保存的设置组ID
由exec函数保存
  • 实际用户ID和实际组ID:标示我们实际上是谁。这两个字段是在登录时读取口令文件中的登录项获得。一般情况下,在一个会话期间,实际用户和实际组用户不会改变;但超级用户的进程可能改变它们。
  • 有效用户ID,有效组ID以及附加组ID:决定了文件访问权限;
  • 保存的设置用户ID、保存的设置组ID:在执行程序时包含了有效用户ID和有效组ID的副本。

文件访问权限

  1. 文件访问权限规则
  • 当进程使用文件名称打开任意类型文件时,对该文件名称中包含的每个目录,包括它可能隐含的当前工作目录应具有执行权限。

例如:

  • 为打开/usr/include/stdio.h文件,需对目录//usr/usr/include具有执行权限。对于stdio.h需要具有对文件本身适当权限,取决于以何种模式打开(只读、读-写等)
  • 若当前目录就是/usr/include,那么为打开stdio.h,需要对当前目录有执行权限。
  • 文件读权限决定进程能否打开文件进行读操作。与open函数的O_RDONLYO_RDWR标志相关。
  • 文件写权限决定进程能否打开文件进行写操作。与open函数的O_WDONLYO_RDWR标志相关
  • open函数指定O_TRUNC标志时,进程对该文件需具有写权限
  • 在目录中创建或删除文件,需对该目录具有写权限和执行权限
  • 使用exec函数执行某个文件时,需对该文件具有执行权限,且该文件须是普通文件
  1. 文件访问时,内核进行的测试
  • 进程每次打开、创建或删除文件时,内核会进行文件访问权限测试,这种测试涉及文件所有者(st_uid和st_gid)、进程的有效ID(有效用户ID和有效组ID)以及进程附加组ID(若支持的话)。两个所有者ID是文件性质,两个附加组ID和附加组ID则是进程性质。
  • 内核进行的测试:
    • 若进程有效用户ID是0(root用户),则可以访问
    • 若进程有效用户ID等于文件owner ID,则该进程拥有owner设置的权限
    • 若进程有效组ID或进程附加组ID之一等于文件group ID,则该进程拥有group设置的权限
    • 若不满足上面3种情况,说明进程拥有的是和others设置的权限

新文件和目录的所有权

  • 当使用opencreate创建新文件时,新文件的owner ID设置为进程的有效用户ID
  • 新文件的组ID,则可能有两个选择:
    • 新文件组ID可以是进程的有效组ID
    • 新文件组ID可以是所在目录的组ID
  • 使用mkdir创建目录,新目录的所有权规则和创建新文件规则相同

access函数

  • access函数是按实际用户ID和实际组ID进行访问权限测试的。(和有效用户ID和有效组ID、保存用户ID和保存组ID区分开)
#include 

//成功返回0,失败返回-1
int access(const char* pathname, int mode);
  • mode取值:表中所列常量按位或
mode 说明
R_OK 测试读权限
W_OK 测试写权限
X_OK 测试执行权限
F_OK 测试文件是否存在
  • 示例代码:
#include 
#include 
#include 

int main(int argc, char* argv[]) {
  if (argc != 2) {
    printf("Usage: %s \n", argv[0]);
    return 0;
  }
  
  // 测试文件是否存在
  if (access(argv[1], F_OK) < 0) {
    printf("%s access F_OK fail\n", argv[1]);
  }else {
    printf("%s is exist\n", argv[1]);
  }
  
  // 测试进程对文件是否有读权限
  if (access(argv[1], R_OK) < 0) {
    printf("%s access R_OK fail\n", argv[1]);
  }else {
    printf("%s read access OK\n", argv[1]);
  }

  // 测试进程是否可以以读模式打开文件
  if (open(argv[1], O_RDONLY) < 0) {
    printf("%s open read fail\n", argv[1]);
  }else {
    printf("open for reading OK\n");
  }
}
  • 运行结果:

https://img-blog.csdnimg.cn/img_convert/30abf0a0eb3ccf84d8de419ad5898f9d.png#clientId=u742770c0-e839-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=306&id=ua7b70b67&margin=[object Object]&name=image.png&originHeight=382&originWidth=701&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71501&status=done&style=none&taskId=u9aff2c84-1518-4c6c-9ad7-69e107ea54c&title=&width=560.8

test.txt的文件权限为rwxrwxrwx,所以运行程序读取test.txt时是可以正确读取打印的。
/etc/shadow文件权限是rw-r-----,所以用zean用户运行程序对该文件没有读取权限,故会显示access failopen fail

umask函数

  • umask函数为进程设置创建文件时默认权限屏蔽字,并返回以前值
#include 

// 返回值:以前文件模式的默认权限屏蔽字
mode_t umask(mode_t cmask);
  • 示例代码:
#include 
#include 
#include 
#include 

// rw-rw-rw-权限
#define RW_RW_RW_ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

int main() {
  // 设置默认权限屏蔽字为000
  umask(0);
  if (creat("foo", RW_RW_RW_) < 0) {
    fprintf(stderr, "create error for foo\n");
  }else {
    fprintf(stdout, "create foo success\n");
  }
  
  // 设置默认权限屏蔽字为066
  umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  if (creat("bar", RW_RW_RW_) < 0) {
    fprintf(stderr, "create error for bar\n");
  }else {
    fprintf(stdout, "create bar success\n");
  }
}
  • 运行结果:

https://img-blog.csdnimg.cn/img_convert/8d1172105ed5a897ec8ce3feb3bac983.png#clientId=u742770c0-e839-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=218&id=u294decad&margin=[object Object]&name=image.png&originHeight=272&originWidth=707&originalType=binary&ratio=1&rotation=0&showTitle=false&size=34525&status=done&style=none&taskId=ua9e3a831-f8c1-4c6e-9a0c-d8b0942b23b&title=&width=565.6

可以看到用户一开始的umask为002;使用umask函数将默认权限屏蔽字设置为0,即不屏蔽任何权限,所以以rw-rw-rw-权限设置创建foo,使用ls -l查看其权限也是rw-rw-rw-
使用umask函数将默认权限屏蔽字设置为066后,屏蔽group和others的读写权限。所以以rw-rw-rw-权限设置创建bar,使用ls -l查看其权限变为rw-------,group和others的读写权限被屏蔽。

从运行umasktest程序的前后两次调用umask命令可以看出:更改进程的默认权限屏蔽字,并不会影响父进程(这里是shell)的默认权限屏蔽字。

chmod和fchmod函数

  • 这两个函数用于修改现有文件的访问权限
#include 
// 根据文件名
int chmod(const char* pathname, mode_t mode);
// 根据文件描述符
int fchmod(int filedes, mode_t mode);
  • 这里参数mode可以参考st_mode(mode_t)权限位相关
  • 示例代码
#include 
#include 

int main() {
  struct stat statbuf;
  
  // 获取foo文件的stat结构体
  if (stat("foo", &statbuf) < 0){
    fprintf(stderr, "stat error for foo\n");
    return 0;
  }
  
  // 将foo文件的group执行权限取消,并设置Set GID权限
  // st_mode中包含了文件原来的权限信息
  if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) {
    fprintf(stderr, "chmod error for foo\n");
  }else {
    fprintf(stdout, "chmod foo success\n");
  }
  
  // 将bar文件权限设置为rw-r--r--
  if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
    fprintf(stderr, "chmod error for bar\n");
  }else {
    fprintf(stdout, "chmod bar success\n");
  }
}
  • 运行结果

https://img-blog.csdnimg.cn/img_convert/bc937d61c3cad19aa1923a3f14099395.png#clientId=u742770c0-e839-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=222&id=u9360a521&margin=[object Object]&name=image.png&originHeight=278&originWidth=645&originalType=binary&ratio=1&rotation=0&showTitle=false&size=34026&status=done&style=none&taskId=u99f88a05-4650-40af-9950-c1c57f2cd80&title=&width=516

可以注意到,ls命令列出的时间和日期并没有改变。因为chmod函数更新的是i节点最近一次被更改时间,系统默认ls -l显示的是最后修改文件内容时间

chown、fchown和lchown函数

  • 用于更改文件用户ID和组ID
#include 
// 以文件名设置
int chown(const char* pathname, uid_t owner, gid_t group);
// 以文件描述符设置
int fchown(int filedes, uid_t owner, gid_t group);
// 指定文件需是链接文件,只改变符号链接本身,不改变符号链接所指向文件
int lchown(const char* pathname, uid_t owner, gid_t group);

若两个参数owner或group中任意一个是-1,则对应ID不变

  • 基于BSD系统一直规定只有超级用户才能更改一个文件owner
  • 基于系统V允许任一用户更改他们所拥有的文件owner
  • _POSIX_CHOWN_RESTRICTED定义在头文件中,其作用:
    • 只有root用户进程可以更改该文件owner
    • 一个非root用户进程,只有在拥有该文件(有效用户ID等于该文件owner ID)或当chown函数参数owner等于-1或文件用户ID,并且参数group等于进程的有效组ID或进程的附加组ID之一时才可以更改文件组ID

_POSIX_CHOWN_RESTRICTED是否有作用,由文件系统决定。当_POSIX_CHOWN_RESTRICTED起作用时,不能更改其他用户文件的用户ID。可以更改你所拥有的文件组ID,但只能改到当前进程用户所属的组。

参考资料:
《UNIX环境高级编程》
《鸟哥 Linux 私房菜:基础版》

你可能感兴趣的:(Linux学习笔记,linux)