文件权限

一、文件信息结构

图1 文件信息结构stat

与文件有关的信息结构,如图1所示,结构的实际定义可能随具体实现会有所不同,但这是基本形式。本节中主要涉及的有st_modest_uidst_gid成员。

图2 获取stat函数

获取文件信息结构stat,有4个stat函数。

stat通过pathname来获得文件相关信息结构stat;

fstat通过文件描述符fd来获得文件相关信息结构stat;

lstat类似于stat,但当命名文件是一个符号链接时,lstat返回该符号链接的有关信息,不是符号链接引用的文件信息【NOFOLLOW】。

fstatat中,fd控制相对路径的起始目录,flag控制是否跟随符号链接【AT_SYMLINK_NOFOLLOW】。

  • 文件类型

(1)普通文件(2)目录文件(3)块特殊文件(4)字符特殊文件(5)FIFO(6)套接字(7)符号链接

文件类型信息包含在stat结构中的st_mode成员中,可用图3的文件类型宏判断,输入为st_mode,如S_ISREG(stat.st_mode)

图3 文件类型宏

 二、与进程相关的ID

与进程相关联的ID有6个或更多,如图4

图4 与进程相关的ID

1、实际用户ID和实际组ID,标识实际上我们是谁,这两个字段在登录时取自口令文件中的登录项。

2、有效用户ID、有效组ID及附属组ID,这3个ID决定了进程的文件访问权限。

即判断文件访问权限是根据进程有效ID文件的ID进行判断的。具体规则后续再展开。

3、保存设置用户ID、保存设置组ID,分别是有效用户ID、有效组ID的副本。这个字段的用处,后续再展开。

 

注意:一般情况下,有效用户ID=实际用户ID,有效组ID=实际组ID

特殊情况下:st_modeset-user-ID位(设置用户位)set-group-ID位(设置组位) 会改变这种情况。

如果文件的设置用户位被设置,那么执行该文件(exec)时,有效用户ID=文件用户ID,而不是有效用户ID=实际用户ID;

如果文件的设置组位被设置,那么执行该文件(exec)时,有效组ID=文件组ID,而不是有效用户ID=实际用户ID。

 

例1:passwd是一个设置用户ID程序,当普通用户进程执行passwd时,有效用户ID更改为文件的用户ID(root),这样就拥有了root特限,可以更改口令文件。

 

  • 保存设置ID的作用

以用户ID为例,组ID效果类似,可推广。

更改用户ID的方法,如图5所示。

图5 更改用户ID的方法

实际的用户ID在登录时获取,有效用户ID=实际用户ID;

除非exec一个文件时,该文件设置了设置用户ID位,有效用户ID=文件的用户ID;

保存设置用户ID从有效用户ID中复制。

这些在前边都介绍过了。

 

当程序需要增加特权或者降低特权时,需要对用户ID或组ID进行更改,以获取合适的访问权限。

这里以用户ID为例,更改用户ID,可以用setuid进行。

(1)若进程具有超级特权,setuid则会更改实际用户ID、有效用户ID、以及保存的设置用户ID为uid。

(2)若没有超级特权,setuid只能更改有效用户ID,而且uid要么为实际用户ID,要么为设置用户ID

 

例2:at程序,可用于调度在哪个时刻运行特定的命令。at文件是root用户所拥有的,且设置用户ID位被设置了。

 运行at程序,过程:

(1)运行at程序,用户ID状态如下

实际用户 ID = 我们的用户ID(未改变)

有效用户ID = root(从at程序文件得来)

保存的设置用户 ID = root(复制有效用户ID)

(2)at先降低自己的特权,调用setuid更改为实际用户ID

实际用户 ID = 我们的用户ID(未改变)

有效用户ID = 我们的用户ID(uid=实际用户ID)

保存的设置用户 ID = root(未改变)

(3)直到需要特权时(更改命令何时的运行配置文件),调用setuid更改为root(uid = 保存的设置用户ID,这也是保存设置用户ID作用的体现)

实际用户 ID = 我们的用户ID(未改变)

有效用户ID = root(uid=保存的设置用户ID)

保存的设置用户 ID = root(未改变)

(4)降低特权,防止对特权的误用

实际用户 ID = 我们的用户ID(未改变)

有效用户ID = 我们的用户ID(uid=实际用户ID)

保存的设置用户 ID = root(未改变)

(5)时间到,守护进程开始用root特权运行,代表用户运行命令(用setuid,将所有用户ID设置为我们的用户ID)

实际用户 ID = 我们的用户ID(root,setuid更改所有)

有效用户ID = 我们的用户ID(root,setuid更改所有)

保存的设置用户 ID = 我们的用户ID(root,setuid更改所有)

 

总结:保存设置用户ID,很多部分是为了实现最小特权

 

三、文件访问权限

每个文件有9个访问权限位,可分为3类,用户读写执行、读写执行、其它读写执行,如图6所示(存储在st_mode)。

 

图5 文件访问权限

 根据前边,知道访问权限测试,是根据进程有效ID(有效用户ID和有效组ID)和文件的ID进行判断的。

(1)进程的有效用户ID是0(超级用户),具有所有访问权限;

(2)进程的有效用户ID等于文件用户ID(stat.st_uid),且文件中用户适当的访问权限位(读写执行)被设置,则允许访问;

(3)进程的有效组ID或附属组ID之一等于文件组ID(stat.st_gid),且文件中组适当的访问权限位(读写执行)被设置,则允许访问;

(4)其它情况,若文件中其它用户适当的访问权限(读写执行)被设置,则允许访问;

  • access和faccessat

access和faccessat函数,可根据进程实际ID来测试访问权限,而不是有效ID

 

图6 access和faccessat函数

 

四、新文件的所有权和权限

所有权:

新文件的用户ID设置为进程有效用户ID

新文件的组ID,可以是进程有效组ID;也可以是所在目录的组ID

注意:Linux3.2.0和Solaris 10,新文件的组ID取决于目录的设置组ID位是否被设置。若被设置,则新文件的组ID是所在目录的组ID。

 

新文件的权限:

umask为文件模式创建屏蔽字,在文件模式创建屏蔽字中位1的位,在文件mode中的相应位一定被关闭。

还有,普通文件文件被创建时,不能拥有执行权限。

常用值有002,022和027。

002屏蔽其它用户的写权限,022屏蔽组成员和其它用户的写权限,027屏蔽组成员的写权限以及其它用户的所有权限。

 

五、更改文件的权限位

 

图7 chmod、fchmod和fchmodat函数

 只有进程的有效用户ID等于文件所有者ID,或者进程具有超级用户权限,才可以更改文件的权限位。

参数mode是一下的常量按位或:

图8 权限位总览

 粘着位作用:

(1)可执行文件,第一次被执行后,程序正文部分还保留在交换区

(2)扩展了使用范围,如果一个目录设置了粘着位,那么改目录下的文件删除有限制条件

拥有此文件 or 拥有此目录 or 是超级用户才能删除。

 

六、更改文件的用户ID和组ID

图9 更改文件用户ID和组ID函数

_POSIX_CHOWN_RESTRICTED限制生效:

(1)只有超级用户可更改用户ID

(2)非超级用户可以更改自己拥有文件的组ID,但只能更改到自己所属的组

 

七、文件权限位总结

图10 文件权限位总结

 

posted @ 2019-01-14 00:08  我是老邱  阅读(685)  评论(0编辑  收藏  举报