7.1 Linux 文件

7.1.1 Linux 文件类型

文件类型是文件元数据之一,在 Inode 中 占 4 位

普通文件、块设备、字符设备、管道、硬链接、套接字、目录文件,用不同符号表示:

文件类型 说明 创建
普通文件 - 文本文件、二进制文件、图片、压缩包 touch,vi,重定向符号
块文件 b 硬件文件,多在/dev fdisk 或建虚拟分区
字符设备文件 c 提供输入输出的串流,键盘、鼠标  
管道文件 p FIFO: First In, First Out mkfifo
链接文件 l * -> **** ln -s
套接字文件 s    
目录文件 d 硬链接数≥2 mkdir

是指 ls -l 返回结果第一列的符号,用于表示文件类型。

文件名之前有英文句号 .,表示 隐藏文件,可以使用 ls -a 来显示。

  • 普通文件

纯文本文件,二进制文件,数据文件

  • 目录文件

目录是一种特殊文件。

  • 链接文件

硬链接、软链接。

  • 设备文件

通常集中在 /dev 目录。

块设备文件 :提供系统随机存取的周边设备。

字符设备文件:键盘、鼠标,这些设备的信息传输是串流的。

  • 套接字文件

SOCKET,可以启动一个程序来监听用户端的访问,用户端就可以通过这个 SOCKET 来进行数据的通讯了。

  • 管道文件

PIPE,又名 FIFO(first-in-first-out)文件。目的在解决多个程序同时存取一个文件所造成的错误问题。

7.1.2 Linux 文件扩展名

Linux 的文件是没有扩展名的,仅为了使用方便才加的。

  • .sh 脚本或批处理文件,用 shell 写成

  • .Z, .tar, .tar.gz, .zip, .tgz 压缩包

  • .html, .php 网页文件

文件真正的执行与否需要权限的规范,与扩展名无关。

7.1.3 Linux 文件名

文件名长度限制

在 Linux 中,对于 EXT2、EXT3、EXT4 以及 XFS 文件系统,针对文件的文件名长度限制为:

单一文件或目录的文件名最长为 255 字节,即 255 个英文字符,或 128 个中文字符。

文件名字符限制

文件名避免特殊字符:? > < ; & ! [ ] | \ ' " ` ( ) { }

7.2 Linux 文件权限

Linux 文件的权限控制,一方面为了数据安全,另一方面便于文件共享。

7.2.1 权限位

权限也是文件元数据之一,在 Inode 中占 12 位,其中:

普通权限 占 9 位

特殊权限 占 3 位

普通权限

普通权限类型

普通权限分 读、写、执行 三种,各占 1 位。

  • 读:Read,用户有权读取文件内容

  • 写:Write,用户有权写入或修改文件内容

  • 执行:eXcecute,用户有权执行文件,或浏览目录中文件列表

文件权限
普通权限组

共有三组普通权限,共 9 位,根据访问对象的不同,分别为:

  • 所有者:Owner,文件的所有者

  • 组:Group,文件的属组

  • 其他人:All other s,所有其他人

每个权限组都有三个完整的权限位,读、写、执行。

特殊权限

文件特殊权限: SUID, SGID, SBIT,各占 1 位。

SUID

SUID,Set ID,文件所有者的 x 位变成 s

[ 作用 ]:

使普通用户可以 临时 借助程序来间接地 修改其无权访问的文件

[ SUID 规则 ]:

  • SUID 权限仅对 二进制程序 有效
  • 用户对该程序必须有可执行权限
  • 本权限仅在程序运行 过程中 临时有效
  • 程序运行期间,执行者具有程序 所有者权限

主要用于文件。可以为目录设置 SUID,但 linux 系统会忽略此标签。

查找所有 SUID/SGID 的程序

find / -perm /6000

SGID

SGID,Set Group ID,属组的 x 位变成 s

SGID 可以针对 文件目录 来设置,作用各不相同。

对可执行文件

SGID 仅对 二进制程序 有效。用户可以不属于程序属组,但对程序必须有 x 权限。

[ 作用 ]:

执行者在程序运行过程中临时获得该程序 属组的权限

对目录

用户有权访问目录,即具有 r x 权限

[ 作用 ]:

在该目录内新建的文件或目录,均 继承其GID,而非用户的 GID。

在该目录新建的文件或目录,均继承其 SGID

SGID 适用 多人合作同一个项目

SBIT

Sticky Bit,其他人的 x 位变为 t

SBIT 只对 目录 有效,对文件无效。

用户需对此目录有 w, x 权限

[ 作用 ]:

用户在该目录新建的文件或目录,只有 自己root 有权删除

SUID/SGID/SBIT 权限设置

这三个特殊权限各自占用一个模式位,位于普通权限之前。

数字表示:

  • SUID = 4

  • SGID = 2

  • SBIT = 1

如 4700 表示该文件权限为 SUID、u=rwx、go= 。

7.2.2 查看文件权限

ls -l 命令以详细格式列出当前目录中的所有文件。

文件属性

7.2.3 权限表示方法

用数字表示

这是一种更接近真实文件系统结构的表示方式。

普通权限共 9 位,因此,实际上保存的是 9 位二进制:

111 100 100

如果把每个权限组的三位二进制数字用一个八进制数字来表示的话,一共只需 3 位数字即可,更简洁:

744

八进制 二进制 含义
0 000 无权限
1 001 x
2 010 w
3 011 wx
4 100 r
5 101 rx
6 110 rw
7 111 rwx

用符号表示

用符号表示是为了以使用者容易理解的方式,更快捷地使用。

如:a+xu+wo-wxu=rwxo=u=rwx,g=rx,o=rx

权限对象

在权限组的基础上,增加了一个 “所有人”。因此平时为方便,用 ugo 表示权限组。

  • u = ,所有者

  • g = group,组

  • o = others,其他人

  • a = all,所有人

权限对象做为参数,如果被省略,默认为 a,即对所有人生效。

操作符号
  • + 赋予权限

  • - 去掉权限

  • = 指定权限

权限

做为参数指定时,可以是 rwxXst 的任意组合,也可为空。可同时指定 多个权限,用 逗号 分隔。

这里除了三种普通权限、三种特殊权限之外,又多了一个 X,但实际上它算不上一种权限,只是一个方便操作的参数。

  • rwx = rwx 基本权限

  • s = SUID 或 SGID,替换所有者或组的 x

  • t = SBit,替换其他人的 x

  • X

X 本身并非代表权限,却可代替 x 来解决一个平时难以解决的问题:

为目录和可执行文件增加执行权限。

对于目录,不管其当前权限如何,为目录增加执行权限;对于文件,如果其 ugo 权限组至少有一个组有执行权限,则 为文件增加执行权限,具体生效的权限组由命令参数指定。而 本没有任何执行权限的文件会被排除,不会为其增加执行权限。

即,针对 大目录树组或他人 设定 执行 权限,同时 避开普通文件 不设。

通常要加上 -R 参数,因为要遍历所有子目录及文件。

本来在这种情况下,通常会使用 chmod -R a+rx . 来实现,但这样一来,该目录及其所有文件均会被设定 x,带来了不必要的安全隐患。

于是可以用 chmod -R a+rX . 来替代。把 x 换成了 X,其效果就完全不同,本来没有任何执行权限的文件,会被排除在外。除此之外,该目录本身、其子目录、原来有可执行权限的文件,其 ugo 均会增加可执行权限。

7.2.4 UMASK

权限掩码的概念

file-creation mode mask,权限掩码,对应所有 12 个权限位

当程序创建一个文件时,必须为文件设定初始的权限,权限掩码就是用来 设定初始权限 用的。

以数字表示时,在普通权限 3 位的基础上,最前边增加 1 位,共四位。第一位永远是 0,可以忽略,后三位代表 ugo

如果掩码中有一位设定为 1,意味着对应的初始权限被 禁用。如果设定为 0,则意味着对应的权限会 由进程或系统来决定

每个 进程 拥有自己的权限掩码,可以用函数调用来修改其设置。如果该进程是一个 shell,则用 umask 命令来设置。因此 umask 对权限掩码的修改往往是 临时性的

如果需要 永久修改 权限掩码,则需要修改 /etc/profile/etc/bashrc 中的 umask 设置。

子进程会 继承 父进程的权限掩码。

权限掩码仅影响 新建的文件,而不会影响现有的文件。

掩码的计算

新建文件其权限位的最终值是使用 位操作 来计算的:

R: (D & (~M))

即,文件权限掩码 M 的按位非默认权限 D 进行按位与计算,得到结果 最终权限 R

默认掩码

目录 默认权限 = 777

文件 默认权限 = 666

超级用户 默认掩码 = 022

普通用户 默认掩码 = 002

计算普通用户新建目录的权限:777 - 002 = 775

🍎 因此,各用户默认权限为:

  • 超级用户 新建目录 = 755

  • 超级用户 新建文件 = 644

  • 普通用户 新建目录 = 775

  • 普通用户 新建文件 = 664

语法

umask 程序用于控制 文件权限掩码,它决定了当前 进程 新建文件时 文件默认权限

umask [ -S ] [ Mask ]

-S 用符号表示当前权限掩码

如果不带参数运行,umask 命令直接显示当前掩码

范例

umask a=rx,ug+w 以符号方式设置

umask 002 以数字方式设置

umask -S 以符号方式显示当前设置

umask g-w 组去掉修改权限

umask -- -w 所有人去掉修改权限

7.2.5 修改文件权限

  • chgrp :修改文件属组

  • chown :修改文件所有者

  • chmod :修改文件权限

CHGRP

修改文件属组。

chgrp [参数] 组 文件

-R 递归处理,将指定目录下的所有文件及子目录一并处理

-v 显示命令执行过程

--reference= 把指定文件或目录的所属群组全部改为和参考文件或目录的所属群组相同

  • 范例

chgrp -R newgroup file

CHGOWN

修改文件的所有者。

chown [参数] 用户 文件

-R 递归处理,将指定目录下的所有文件及子目录一并处理

-v 显示命令执行过程

--reference= 把指定文件或目录的所属群组全部改为和参考文件或目录的所属群组相同

  • 范例

chown -R file 修改所有者

chown -R new:newgroup file 修改所有者及属组

chown -R :newgroup file 修改属组,同 chgrp

把文件复制给其它组或人时,需要修改所有者及属组,以便对方有权访问。

CHMOD

chmod 用于修改文件的权限位。

chmod [参数] 文件名

  • 范例

chmod -R 777 /path/ 递归修改目录中所有文件

chmod u=rwx,go=rx file

chmod a+w file

chmod a-x file

7.3 文件权限 vs 目录权限

Linux 系统中,因为文件名与实际数据是分开保存的,于是,针对文件名的权限针对文件数据的权限 被彻底 分开管理

具体来说,文件名由 目录项 控制,文件数据由 文件 Inode 控制。

7.3.1 文件的权限

文件的权限影响的是对 文件数据 的操作。

  • r = 可读取文件内容

  • w = 可编辑、新增、修改(不含删除);

  • x = 可被执行

7.3.2 目录的权限

目录的权限影响的是对目录对象的 文件名文件 Inode 的操作。

目录文件

为了生成目录树,文件系统会把文件名保存在目录文件中。

目录文件结构

同其他文件一样,每个 目录文件 也有一个自己的 Inode,其中保存了目录文件的所有 元数据,包括 “数据块指针,权限,所有者,修改时间” 等。

目录文件的数据块 中保存的是其独特的文件内容:目录项,即 文件名 - Inode 编号 形式的数据,仅此而已。

而目录项中的文件名,其真实的文件属性,以及其数据块的指针都保存在它自己的 Inode 当中。

一个文件的文件名和其属性、数据就这样被分割开来,很大程度上保证了数据的安全。

目录损坏

目录文件中的 目录项 是系统中文件名和真实数据 唯一的连接

如果目录文件的 Inode 或数据块被损坏,通常只是丢失了文件名,这些文件的真实数据及属性因为保存在其它的块中,很有可能没有丢失。此时,文件的 Inode 变成了孤儿,可以用 fsck 等工具来恢复这些文件数据。

文件属性

读取目录文件,只能获得文件名和 Inode 编号,无法得知文件的属性(文件类型、所有者、权限、修改时间、大小等),要想了解这些信息,用户须有权访问该文件的 Inode。根据目录项中的 Inode 编号,找到该文件的 Inode,就可以查看其中保存的各个元数据。

正因为如此,查看文件的属性需要额外的操作,所以 ls -i 会比 ls -l 更快地返回结果,目录越复杂效果越明显。

递归目录树

系统如何通过一个绝对路径来查找文件的真实数据?

从根目录开始,根目录文件的 Inode 编号均为 2,如果对根目录有执行权限,则可以查看根目录的 Inode,通过其中的指针找到根目录文件数据块,查看文件内容(目录项列表),从中找到二级目录及其 Inode 编号;

如果有执行权限,则可查看二级目录 Inode,通过指针找到二级目录文件数据块,查看目录项列表,在目录项列表中继续查找下一级目录。

重复以上步骤,直到从目录项中找到文件名。

递归目录树

目录文件的权限

读权限
  • 有权读取目录项

如果对目录只有读取权限,则允许 读取该目录中的文件名,用 ls -l 能够查看目录中的文件列表,但所有的属性均无法显示,用 ? 占位。

tmp]$ ll tt
ls: cannot access tt/a: Permission denied
ls: cannot access tt/c: Permission denied
total 0
-????????? ? ? ? ?            ? a
-????????? ? ? ? ?            ? c

无法显示文件属性的原因是:无权读取目录中所有文件的 Inode。

写权限

写权限要想生效,需要同时 有执行权限。如果没有执行权限,则单纯的写权限无任何意义。

为什么必须有执行权限的配合,写权限才能生效?因为涉及到两个因素,一个是新建、移动、删除文件以后,需要对文件 Inode 中的链接数的更新;另一个是重命名文件时,rename 的系统调用需要前后两个路径名称(pathnames)做参数,路径名称的获得要靠执行权限通过对目录树的递归来获得。

  • 有权修改目录文件属性及目录项

新建 文件:增加目录项

重命名 已存在的文件:修改目录项

删除 现有文件:删除目录项

移动 目录中的文件:修改或删除目录项

执行权限
  • 有权访问目录项中的 Inode

最形象的描述:对目录的执行权限,允许 穿透该目录,或 进入该目录

访问目录中文件或子目录文件的 Inode,可以查看文件属性、权限、修改日期、所有者等,同时还可以通过指针来查看文件的数据块的内容。如果是目录文件(子目录),就可以查看子目录中的文件列表,从而 递归目录树,最后,逐级找到目标文件的 Inode,因此执行权限也叫 搜索权限,。

因此,结合上文的 “系统查找文件的流程”,用户要想访问某一个文件,其上层的每一级目录必须都对用户开放执行权限,否则文件系统就无法找到文件的 Inode。

允许 将目录做为工作目录,可以 cd 进入,并可以 访问文件

该权限对于以下操作是必需的:

  • 访问其中的文件,包括读、写、执行。

  • 新建、重命名、删除文件

🌟 如果用户对 目录写、执行 权限,即使他对目录中的文件没有任何权限,也能轻松地 删除文件。这种情况可以用 SBIT 来化解。

🌟 如果用户对 目录 只有 执行 权限,对 文件 权限,他 无法删除 文件,却可以往文件中 写入数据,如 echo > 'something new'echo >> 'something newer'。但无法用 cat 查看文件内容,如果对文件有了 权限,就可以查看内容,同时也可以用 vi 来直接编辑文件内容。

SBIT

该目录中的对象,除超级用户以外,只能由其所有者本人删除,其他人无权删除。

7.3.3 文件权限与目录权限对比

目录文件权限的作用
目录文件权限的作用

文件操作所需权限:

操作 /dir1 /dir1/file1 /dir2
查看 file1 内容 x r -
修改 file1 内容 x rw -
执行 file1 x rx -
删除 file1 wx - -
将 file1 复制到 /dir2 x r wx

如果目录文件没有 r 权限,只是无法查看文件列表(文件名)而已。只要有 wx,并知道文件名,就可以进行文件的读取、修改、执行、删除、复制等操作。

7.4 文件的属性

7.4.1 CHATTR

chattr 命令用于修改文件属性,是 EXT 时期的工具,在 XFS 中仅支持部份参数。

语法

chattr [ -RVf ] [ -v version ] [ -p project ] [ mode ] files...

A 锁定 atime,可减少 I/O。

a 只能追加 内容,不能删除文件,不能修改,限 超级用户 使用

d 不被 dump 备份

i 禁止 删除、改名、链接、修改,限 超级用户 使用

S 将文件的修改 同步 写入磁盘。

EXT 文件系统支持所有参数,XFS 仅支持以上 AadiS 5 个参数。

c 读之前自动解压,写之前先压缩

s 如果删除文件,会被完全移除出硬盘空间,无法恢复

u 删除文件后,数据仍存在磁盘,可以恢复

  • 范例

sudo chattr +i file 锁定文件,禁止改名、修改、删除、链接

sudo chattr +a file 文件只允许追加内容,不能删除、修改

chattr +d file 不被 dump 备份

chattr +A file 锁定 atime,减少 IO

chattr +S file 有变化时 同步 写入磁盘

LSATTR

查看文件属性

lsattr [-adR] 文件或目录

-a 包括隐藏文件

-d 仅列出目录本身的属性

-R 包括子目录

7.4.2 扩展属性

扩展属性概念

扩展属性由 属性名:值 这样成对的信息组成,可以永久地关联到文件和目录上。可以定义一个属性,也可以取消定义。如果属性被定义,其值 允许为空

普通的文件属性通常于系统中所有的 Inode 关联,扩展属性是普通属性的扩充。经常用来 为文件系统提供额外的功能。比如可以扩展 ACL 额外的安全特性。

对文件或目录有搜索权限的用户,可以查看其属性列表。

支持扩展属性的文件系统主要有 EXT,XFS,JFS 等。

cprsync 等类似的命令,默认不会保留原文件的扩展属性,需要加特定的参数:

cp -arsync -X

扩展属性的命名空间

属性名称是以非 0 字符结束的字符串,属性名称必须符合 命名空间.属性 的格式,如 .mime_type, trusted.md5sum, system.posix_acl_access, security.selinux

命名空间的机制是为了定义不同类别的扩展属性,之所以要分类,是因为控制每一类命名空间的扩展属性,所需要的 权限 和带来的 功能 是不同的。

共有四类扩展属性:安全(security)、系统(system)、信任(trusted)、用户()

扩展安全属性

扩展安全属性其命名空间由内核的安全模块使用,如 SELinux。对安全属性的读、写权限决定于安全模块对每个安全属性部署的策略。如果没有安全模块被加载,所有进程对扩展安全属性都有读取权限,有 CAP_SYS_ADMIN 能力(capability)的进程则有写的权限。

扩展系统属性

内核使用扩展系统属性来保存系统对象,如 ACL、Capabilities。读、写权限决定于文件系统在内核中,针对每一个系统属性所部署的策略。

可信扩展属性

只有具备 CAP_SYS_ADMIN 能力的进程才能看到,并可读取可信扩展属性,通常是超级用户才有这个能力。这类属性用于在用户空间部署机制,在扩展属性中保存的信息是普通的进程本来无法访问的。

扩展用户属性

扩展用户属性可以用来给文件和目录附加一些任意的信息,如 mime 类型、文件的字符集、文件的编码等。对于用户属性的访问权限由文件的权限位控制。

普通文件及目录其权限位所代表的意思,与特殊文件及符号链接其权限位所代表的意思有所不同:

对于 普通文件及目录,其权限位定义了对 文件内容 的访问;

对于 设备文件,其权限位定义的是对于其所描述的 设备 的访问;

对于 符号链接,其权限位在访问权限检查中 不起作用

这些区别将允许用户消耗文件系统资源时,不受磁盘配额的控制。基于这个原因,扩展用户属性仅限于普通文件和目录使用,并且只有 所有者SBIT 有权访问。

文件系统应用区别

内核与文件系统会限制扩展属性的数量及大小。

EXT2、EXT3、REISERFS 这些文件系统在挂载时必须使用 _xattr 参数,扩展属性才能启用。

EXT 中,每个扩展属性不能超过一个块大小。

在 XFS、REISERFS 中,对扩展属性的数量和大小没有限制,而且用于保存扩展属性的磁盘空间可以随时调整。

SETFATTR

使用 setfattr 来设置扩展属性

setfattr [-h] -n name [-v value] pathname...

-n 指定属性名,用户扩展属性必须用前缀 . 来命名

-v 指定属性的值

-x 删除指定扩展属性,接属性名

  • 范例

setfattr -n .cell -v "13099999999" file

7.5 ACL 权限控制

Linux 传统的权限控制是针对文件的,而无法 针对某一个用户或某一个组

7.5.1 ACL 简介

Access Control List

ACL 分两类:访问 ACL默认 ACL

访问 ACL 用于控制特定 文件或目录 的访问权限。

默认 ACL 是专门针对 目录 的,用于控制目录中新建的文件其默认的访问 ACL。

如果某文件没有访问 ACL,它会使用所在目录的默认 ACL。

默认 ACL 是可选的。

ACL 条目的结构

ACL 是由一系列的访问条目(Access Entry)组成,而每个访问条目又由三部分组成:

Entry Tag Type : Qualifier : Permission

条目标签类型 : 特定对象(可选) : 权限

条目标签类型

ACL_ACL_GROUP 开头的类型需指定具体的用户或组,其它类型则不用。 。

ACL__OBJ:文件 所有者

ACL_特定用户

ACL_GROUP_OBJ:文件 属组

ACL_GROUP特定组

ACL_MASK有效权限掩码,用于限制除所有者以外的,其他用户或组的 最大权限

ACL_OTHER:其他人的权限

特定对象

指的就是要设定权限的具体的对象,即具体的用户或组,可以是用户名或组名,也可以是 UID 或 GID。

权限

权限可以用符号表示,也可以用数字表示。

条目的格式

u:<用户>:<权限>用户 设置 ACL,可以指定用户名或 UID

g:<组>:<权限> 设置 ACL,可以指定组名或 GID

m:<权限> 设置 有效权限掩码

o:<权限> 为组以外的 其他人 设置 ACL。

如果有多个条目,可以用逗号分隔。

ACL 使用规范

  • 每个 ACL 至少包括三个条目,即所有者、属组、其他人的权限。

  • 针对特定用户的条目为可选

  • 如果指定了特定用户或组,则必须指定有效权限掩码的权限

  • 如果没有指定任何特定用户或组,则有效权限掩码为可选

  • 针对同一特定用户或组的条目不能超过一条

ACL 与权限位

由 ACL 定义的权限 是 文件权限位定义的权限 的 超集,即 ACL 权限 包括 文件普通权限。

在文件的所有者、属组和其他人的权限与特定的 ACL 权限之间有对应的关系:

  • 所有者权限 = ACL__OBJ

  • 如果有 ACL_MASK,属组权限 = ACL_MASK;如果没有,属组权限 = ACL_GROUP_OBJ

  • 其他人权限 = ACL_OTHER_OBJ

ugo 的权限 永远 与对应的 ACL 条目相 匹配。修改文件权限会导致对应的 ACL 条目的改变,修改 ACL 条目同样会导致文件权限的改变。

ACL 对象的建立与默认 ACL

当运行 creat()mkdir()mknod()mkfifo()open() 等函数时,文件对象的访问 ACL 会被初始化。

  • 如果有默认 ACL 与目录关联,用来新建文件的函数所用的 mode 参数,以及目录的默认 ACL 被用来决定新建对象的 ACL:

    1. 新建对象会继承目录的默认 ACL,将其做为自己的访问 ACL

    2. 访问 ACL 条目对应的文件权限位会被修改,以保证其权限符合 mode 参数的要求

  • 如果没有默认 ACL 与目录关联,mode 参数和 umask 会被用来决定新建对象的 ACL:

    1. 新建对象被分配给一个访问 ACL,其中包括 ACL__OBJ, ACL_GROUP_OBJ, ACL_OTHER 这三种类型的条目,这些条目的权限根据 umask 来设定。

    2. 对应文件权限位的 ACL 条目会被修改,以保证其权限符合 mode 参数的要求

访问权限检查机制

进程会针对由 ACL 保护的文件对象发起 读、写、执行、查找 的访问请求。访问检查机制会判断是否准许该请求。

ACL 检查机制

ACL 对文件操作的影响

在支持 ACL 的系统中,lscpmv 这些命令的行为会发生变化:

  • 如果文件含有默认 ACL,或其访问 ACL 包含三个基本条目以外的 额外条目ls -l 命令会在权限后面 显示加号 +

  • 如果 cp 命令使用了 -p 参数,则会在复制时 保留 ACL

  • mv 命令 始终会保留 ACL

7.5.2 ACL 的查看

查看当前系统是否支持 ACL

dmesg | grep -i acl

GETFACL

getfacl 用于查看文件的 ACL 条目

getfacl filename

7.3.3 ACL 的设置

ACL 的启用

  • 对文件或目录应用 ACL 之前,相应的分区通常需要以支持 ACL 的方式挂载。

可以在 /etc/fstab 中的条目中,加上 acl 参数。

LABEL=/work /work ext3 acl 1 2

  • 当前的大部分发行版已经默认开启了 ACL

dmesg | grep -i acl 可以查看当前系统是否支持 ACL。

SETFACL 语法

setfacl 用于设置、修改、删除普通文件和目录的访问控制列表。

setfacl [-bkRd] [{-m|-x} acl参数] 目标文件名

setfacl -m <条目> <文件>

选项

-m 修改 ACL 条目

-x 删除 ACL 条目

-b 删除所有 的 ACL 设置

-R 递归 设置 ACL

-d 设置目录的 默认 ACL

-k 删除默认 ACL

--set--set-file 用于设置文件或目录的 ACL 条目,先前的设定将被覆盖

-M 修改 ACL 条目,从文件或 STDIN 读取 ACL 条目

-X 删除 ACL 条目,从文件或 STDIN 读取 ACL 条目

当使用 -M-X 选项从文件中读取规则时,setfacl 接受 getfacl 命令输出的格式。每行至少一条规则,以 # 开始的行将被视为注释。

范例

  • 为指定用户设定权限

setfacl -m u:1:rx file

  • 为文件所有者设定权限

setfacl -m u::rwx file

u 后面留空,表示针对文件 所有者

  • 为指定用户设定权限,空

setfacl -m u:pro3:- /srv/projecta

设置用户对目录 无任何权限,权限字段用 -,不能留空。

  • 为指定组设定权限

setfacl -m g:mygroup1:rx file

  • 设定有效权限掩码

setfacl -m m:r file

借助 mask 来设定最大权限,可以避免权限误分配。

  • 删除指定用户权限

setfacl -x u:500 /project/somefile

  • 为目录设定默认 ACL

通过设置目录对于特定用户的默认权限,使这些用户在目录内新建的文件能够继承其 ACL。

只需在规则前加上 d:

setfacl -m d:u:my1:rx /srv/projecta

7.6 切换用户

7.6.1 帐号与系统安全

养成良好的工作习惯,是保证系统安全的第一步。

  • 以普通用户进行日常工作,需要时才切换为超级用户

  • 用较低权限的系统帐号启动系统服务

  • 设置程序禁止用 root 登陆

7.6.2 SU

su 在某个登陆会话中,变成其他用户。

su [options] [name]

如果不指定用户名,则会切换到 root。

-c command 临时使用指定用户的 shell 运行命令

-/-l 以 login shell 方式切换,提供该用户登陆后的环境。

-m 保留当前的环境变量($PATH, $IFS 除外)

范例

su

以 non-login shell 方式切换 root,环境变量仍为原用户的

su -

用 login shell 切换 root,环境变量更新为 root 的

su - -c "head -n 3 /etc/shadow"

临时用 root 身份执行,命令完成之后仍是原身份

su -l user1

以 login shell 方式切换为其他用户,获得新用户环境变量

7.6.3 sudo

sudo 会根据现有安全策略,允许特定用户以他人身份执行命令。

系统会使用用户的真实 UID 来比对安全策略。

sudo 支持插件,可以使用第三方插件无缝地使用自定义安全策略,并可记录 I/O 日志。

默认的安全策略保存在 /etc/sudoers。安全策略决定了用户可以享有的特权,并规定了用户如何验证身份,可以使用密码或其他验证机制,同时可设置超时退出。

可以在安全策略中设置证书缓存的时间,在此期间使用 sudo 无需再次输入密码,默认为 5 分钟。使用 sudo -v 可以更新证书缓存。

语法

sudo [-b] [-u 新用户帐号]

-b 把命令置于后台运行

-u 指定切换的用户,省略则切换为 root

范例

  • 以其他身份创建文件

sudo -u sshd touch /tmp/mysshd

  • 以其他身份执行脚本

sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"

sudo 执行的流程

  1. 当用户执行 sudo 时,系统检查 /etc/sudoers 文件,以确定该用户有权限。

  2. 确定用户权限后,如不是 root,要求用户输入用户自己的密码。

  3. 若密码正确,开始执行 sudo 后面的命令。

  4. 若切换的目标身份与执行者身份相同,无需密码。

visudo

visudo 用于以安全的方式编辑 /etc/sudoers。实际上是调用 vi 来修改 /etc/sudoers ,但退出之前会 自动检查语法

/etc/sudoers 的结构

典型的 /etc/sudoers 结构为:

Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

root    ALL=(ALL:ALL) ALL

%admin ALL=(ALL) ALL
%sudo   ALL=(ALL:ALL) ALL

#includedir /etc/sudoers.d
系统默认设置
  • env_reset

用于重置终端的环境变量,清除所有自定义变量。避免潜在的有危险的环境变量影响 sudo 的会话。

  • mail_badpass

用于告诉系统,如果输错 sudo 密码,就给 root 发邮件。

  • secure_path

指定 $PATH 变量的值。

用户权限设置

格式为:

user1 ALL=(ALL:ALL) ALL

用户名 适用主机名=(可切换成的用户名:可切换成的组名) 授权使用的命令

ALL 表示任意的。

组权限设置

与用户权限设置相似,只是以 % 开头,表示这是组的名字。

引用目录

虽然以 # 开头,但不是注释,所引用的目录 /etc/sudoers.d 会被读取、应用。

该目录中的所有文件使用与 /etc/sudoers 同样的规范,只要目录中的文件名不以 ~ 结尾,不含有 .,就会被读取并做为配置文件应用给 sudo

范例

  • 指定用户

user1 ALL=(ALL) ALL

  • 群组

%wheel ALL=(ALL) ALL

任何加入该群组的用户,均能使用 sudo 切换任何身份来操作任何命令。

📕 从 CentOS 7 开始,默认开放 %wheel 群组的权限。

  • 群组无需密码

%wheel ALL=(ALL) NOPASSWD: ALL

  • 限定命令

my1 ALL=(root) !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

命令须用绝对路径描述,只能切换成 root 使用 passwd 这一个命令,无法修改 root 密码。

  • 批量新建 sudoers

要把 多个用户 加入 sudoers,可用 visudo 通过创建 用户别名命令别名 来实现。

_Alias ADMPW = pro1, pro2, pro3, my1, my2

定义帐号别名

Cmnd_Alias ADMPWCOM = !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

定义命令别名

ADMPW ALL=(root) ADMPWCOM

别名必须 全部大写

  • 无需管理员密码切换成 root

sudo 结合 su 使用

在需要执行大量 root 的工作时:

_Alias ADMINS = pro1, pro2, pro3, my1

ADMINS ALL=(root) /bin/su -

用户使用 sudo su - 仅需自己的密码,就可以切换为 root。