24.3. 处理 ACL

表 24.1 “ACL 项类型” 总结了 ACL 项 6 种可能出现的类型,每种类型都定义了一个用户或一组用户的权限。拥有者项定义了拥有该文件或目录的用户的权限。所属组项定义了文件所属组的权限。超级用户可以使用 chownchgrp 更改拥有者或所属组,而在这种情况下,拥有者和所属组项表示新的拥有者和所属组。每个已命名用户项定义了在该项的限定符字段中指定的用户的权限,该限定符字段即 表 24.1 “ACL 项类型” 中以文本形式显示的中间字段。每个已命名组项定义了在该项的限定符字段中指定的组的权限。只有已命名用户和已命名组项具有非空的限定符字段。其他项定义了所有其他用户的权限。

通过定义这些项中的有效权限和要屏蔽的权限,掩码项进一步限制了已命名用户已命名组所属组项授予的权限。如果权限同时存在于上述项之一和掩码中,它们就是有效的。仅包含在屏蔽或实际项中的权限是无效的 — 表示未授予这些权限。拥有者所属组项中定义的所有权限始终有效。表 24.2 “屏蔽访问权限” 中的示例说明了这种机制。

ACL 有两种基本类别:一种是最小 ACL,仅包含用于类型拥有者所属组其他的项,对应于文件和目录的传统权限位。另一种是扩展 ACL,它比前一种要复杂得多。它必须包含一个掩码项,并可能包含若干已命名用户已命名组类型的项。

表 24.1. ACL 项类型

类型

文本形式

拥有者

user::rwx

已命名用户

user:name:rwx

所属组

group::rwx

已命名组

group:name:rwx

掩码

mask::rwx

其他

other::rwx

表 24.2. 屏蔽访问权限

项类型

文本形式

权限

已命名用户

user:geeko:r-x

r-x

掩码

mask::rw-

rw-

有效权限:

r--

24.3.1. ACL 项和文件方式权限位

图 24.1 “最小 ACL:ACL 项(对照权限位)”图 24.2 “扩展 ACL:ACL 项(对照权限位)”说明了最小 ACL 和扩展 ACL 这两种情况。这些图分为三块 — 左边一块显示 ACL 项的类型规范,中间一块显示一个示例 ACL,右边一块显示对应于传统权限概念的各个权限位(如 ls -l 所显示的)。在这两种情况下,拥有者权限均被映射到 ACL 拥有者项。其他类别权限也被映射到各自的 ACL 项。但是,组类别权限的映射在这两种情况中是不同的。

图 24.1. 最小 ACL:ACL 项(对照权限位)

最小 ACL:ACL 项(对照权限位)

对于最小 ACL(没有屏蔽),组类别许可权限被映射到 ACL 的所属组项。图 24.1 “最小 ACL:ACL 项(对照权限位)”中显示了这一工具。对于扩展 ACL(具有屏蔽),组类别许可权限被映射到屏蔽项。图 24.2 “扩展 ACL:ACL 项(对照权限位)”中显示了这一工具。

图 24.2. 扩展 ACL:ACL 项(对照权限位)

扩展 ACL:ACL 项(对照权限位)

不管应用程序是否具有 ACL 支持,这种映射方式都可以确保应用程序的流畅交互。通过权限位方式分配的访问权限表示通过 ACL 所进行的所有其他“微调”的上限。对权限位的更改将由 ACL 反映出来,反之亦然。

24.3.2. 具有访问 ACL 的目录

以下示例演示了访问 ACL 的处理:

在创建目录之前,使用 umask 命令来定义每次创建文件对象时应屏蔽哪些访问权限。命令 umask 027 设置了默认权限,即为拥有者分配全部权限 (0),拒绝组写访问 (2),并且不为其他用户分配任何权限 (7)。umask 实际上屏蔽了相应的权限位或将它们关闭。有关详细信息,请参考相应的手册页 (man umask)。

mkdir mydir 应创建具有由 umask 设置的默认权限的 mydir 目录。使用 ls -dl mydir 来检查是否已正确分配所有权限。该示例的输入为:

drwxr-x--- ... tux project3 ... mydir

使用 getfacl mydir,检查 ACL 的初始状态。这样会得出如下信息:

# file:mydir 
# owner:tux 
# group:project3 
user::rwx 
group::r-x 
other::--- 

getfacl 的输出准确地反映了 第 24.3.1 节 “ACL 项和文件方式权限位” 中描述的权限位与 ACL 项之间的映射。输出的前三行显示了目录的名称、拥有者和所属组。随后三行包含三个 ACL 项,即拥有者所属组其他。事实上,对于最小 ACL,getfacl 命令不会生成您使用 ls 所不能获得的任何信息。

使用以下命令修改 ACL,为附加用户 geeko 和附加组 mascots 指派读、写和执行权限:

setfacl -m user:geeko:rwx,group:mascots:rwx mydir

选项 -m 提示 setfacl 修改现有的 ACL。以下参数指示要修改的 ACL 项(各项之间用逗号隔开)。最后部分指定了应该对其应用这些修改的目录的名称。使用 getfacl 命令来查看所生成的 ACL。

# file:mydir 
# owner:tux 
# group:project3 
user::rwx 
user:geeko:rwx 
group::r-x 
group:mascots:rwx 
mask::rwx 
other::--- 

除了为用户 geeko 和组 mascots 创建的项外,还生成了一个掩码项。系统自动设置此掩码项,以便使所有权限生效。setfacl 自动使现有的掩码项与已修改的设置相适应,但前提是不要用 -n 取消此功能。掩码组类别中的所有项定义了最大有效访问权限。其中包括已命名用户已命名组所属组。由 ls -dl mydir 显示的组类别权限位现在与掩码项相对应。

drwxrwx---+ ... tux project3 ... mydir 

输出的第一栏现在包含一个附加的 +,表明此项存在一个扩展 ACL。

根据 ls 命令的输出,掩码项的权限包含写访问权限。传统情况下,这样的权限位意味着所属组(这里是 project3)也具有对 mydir 目录的写访问权限。但是,所属组的有效访问权限对应于为所属组屏蔽定义的许可权限的重叠部分 — 在我们的示例中是 r-x(参见表 24.2 “屏蔽访问权限”)。对本例中的所属组的有效权限而言,即使是在添加了 ACL 项之后,也未发生任何改变。

setfaclchmod 编辑掩码项。例如,使用 chmod g-w mydirls -dl mydir 输出以下结果:

drwxr-x---+ ... tux project3 ... mydir 

getfacl mydir 提供以下输出:

# file:mydir 
# owner:tux 
# group:project3 
user::rwx 
user:geeko:rwx          # effective:r-x 
group::r-x 
group:mascots:rwx      # effective:r-x 
mask::r-x 
other::--- 

执行 chmod 命令将写权限从组类别位去除后,从 ls 命令的输出就足可看出掩码位肯定已被相应地更改了:写权限再次限于 mydir 的拥有者。getfacl 的输出证实了这一点。这个输出包含了对有效权限位与原始权限不对应的所有项的注释,因为已根据掩码项对它们进行了过滤。可以随时用 chmod g+w mydir 来恢复原始权限。

24.3.3. 具有默认 ACL 的目录

目录可以具有默认 ACL,这是一种特殊的 ACL,它定义的是此目录下的对象在创建时继承的访问权限。默认 ACL 影响子目录和文件。

24.3.3.1. 默认 ACL 的效果

将目录的默认 ACL 的权限传递到其中的文件和子目录时,有两种不同的方式:

  • 子目录继承父目录的默认 ACL 作为其默认 ACL 和访问 ACL。

  • 文件继承默认 ACL 作为其访问 ACL。

创建文件系统对象的所有系统调用都使用 mode 参数,该参数定义新创建的文件系统对象的访问权限。如果父目录没有默认 ACL,则从 mode 参数传递的权限中去除 umask 定义的权限位,同时将结果分配到新对象。如果父目录存在默认 ACL,则分配到新对象的权限位对应于 mode 参数的权限和默认 ACL 中定义的权限的重叠部分。这种情况下忽略了 umask

24.3.3.2. 默认 ACL 的应用

以下三个示例说明了目录和默认 ACL 的主要操作:

  1. 将默认 ACL 添加到现有目录 mydir,语句为:

    setfacl -d -m group:mascots:r-x mydir 

    setfacl 命令的 -d 选项使 setfacl 在默认 ACL 中执行以下修改(选项 -m)。

    仔细查看此命令的结果:

    getfacl mydir
    
    # file:mydir 
    # owner:tux 
    # group:project3 
    user::rwx 
    user:geeko:rwx 
    group::r-x 
    group:mascots:rwx 
    mask::rwx 
    other::--- 
    default:user::rwx 
    default:group::r-x 
    default:group:mascots:r-x 
    default:mask::r-x 
    default:other::--- 

    getfacl 返回访问 ACL 和默认 ACL。默认 ACL 由以 default 开头的所有行组成。虽然您只是对 mascots 组的一个项执行 setfacl 命令来创建默认 ACL,但 setfacl 将自动复制访问 ACL 中的所有其他项来创建有效的默认 ACL。默认 ACL 对访问权限没有直接效果。它们只在创建文件系统对象时起作用。这些新对象只从其父目录的默认 ACL 中继承权限。

  2. 在下一个示例中,我们将使用 mkdirmydir 中创建一个子目录,它将继承默认 ACL。

    mkdir mydir/mysubdir
    
    getfacl mydir/mysubdir 
    
    # file:mydir/mysubdir 
    # owner:tux 
    # group:project3 
    user::rwx 
    group::r-x 
    group:mascots:r-x 
    mask::r-x 
    other::--- 
    default:user::rwx 
    default:group::r-x 
    default:group:mascots:r-x 
    default:mask::r-x 
    default:other::--- 

    根据预期,新创建的子目录 mysubdir 具有父目录的默认 ACL 的权限。mysubdir 的访问 ACL 准确反映了 mydir 的默认 ACL。该目录将向其从属对象传递的默认 ACL 也是相同的。

  3. 使用 touchmydir 目录中创建一个文件,例如 touch mydir/myfilels -l mydir/myfile 输出以下结果:

    -rw-r-----+ ... tux project3 ... mydir/myfile 

    getfacl mydir/myfile 的输出是:

    # file:mydir/myfile 
    # owner:tux 
    # group:project3 user::rw- 
    group::r-x          # effective:r-- 
    group:mascots:r-x   # effective:r-- 
    mask::r-- 
    other::--- 

    当创建新文件时,touch 使用值为 0666mode,这意味所创建的新文件具有用于所有用户类别的读和写权限,前提是 umask 或默认 ACL 中不存在任何其他限制(请参见 第 24.3.3.1 节 “默认 ACL 的效果”)。实际上,这意味着 mode 值中不包含的所有访问权限均将从各自的 ACL 项中去除。虽然没有从组类别的 ACL 项中去除任何权限,但仍修改了掩码项来屏蔽不在 mode 中设置的权限。

    这种方式确保应用程序(如编译器)与 ACL 的流畅交互。您可以创建具有有限访问权限的文件,然后将其标记为可执行文件。mask 机制确保适当的用户和组可以在需要时执行它们。

24.3.4. ACL 检查算法

在为任何进程或应用程序授予访问受 ACL 保护的文件系统对象的权限之前,将应用检查算法。作为一条基本规则,将按以下顺序检查 ACL 项:拥有者已命名用户所属组已命名组,以及其他。访问将根据最适合进程的项进行处理。权限不能累加。

如果某个进程属于多个组并且潜在适合多个项,情况会更为复杂。这时将从具有所需权限的合适项中随机选择一个。它与是哪些项触发了最终结果“已授权访问”无关。同样,如果合适的项中没有一个包含所需的权限,则随机选择的项将触发最终结果“访问被拒绝”。