19 Linux 中的访问控制列表 #
可以将 POSIX ACL(访问控制列表)作为文件系统对象的传统权限概念的扩展来使用。相较于采用传统权限概念,利用 ACL 可以更灵活地定义权限。
POSIX ACL 这一术语表明它是一种真正的 POSIX(可移植操作系统接口)标准。由于多种原因,相应的标准草案 POSIX 1003.1e 和 POSIX 1003.2c 已被撤消。但是,在属于 Unix 系列的许多系统上使用的 ACL 都基于这两个草案,并且本章中介绍的文件系统 ACL 的实施也遵照这两个标准。
19.1 传统文件权限 #
SUSE Linux Enterprise Server 中包含的所有文件的权限都是精心选择的。在安装其他软件或文件期间,请在设置权限时格外小心。请始终在 ls
命令中使用 -l
选项,以立即检测出任何不正确的文件权限。错误的文件属性不仅意味着文件可能被更改或删除,修改的文件可能会由 root
执行,或者攻击者可能会通过修改配置文件来劫持服务。这会显著增加受到攻击的风险。
SUSE® Linux Enterprise Server 系统包含 permissions
、permissions.easy
、permissions.secure
和 permissions.paranoid
文件,它们全部位于 /etc
目录中。这些文件用于定义特殊权限,例如全局可写目录或针对文件的 setuser ID 位。设置了 setuser ID 位的程序不会使用启动它的用户的权限运行,而是使用文件拥有者(通常是 root
)的权限运行。管理员可以使用 /etc/permissions.local
文件添加自己的设置。
要定义提供的其中一个配置文件,请在 YaST 的/etc/permissions
中的注释,或查阅 man chmod
。
可在 GNU Coreutils 信息页“节点文件权限”(info coreutils "File permissions"
) 中找到有关传统文件权限的详细信息。更多高级功能有 setuid、setgid 和粘滞位。
19.1.1 setuid 位 #
在某些情况下,访问权限可能过于严格。因此,Linux 另有一些设置,允许为执行特定操作临时更改当前用户和组标识。例如,passwd
程序通常要求拥有根权限才能访问 /etc/passwd
。此文件包含一些重要信息,如用户主目录及用户和组 ID。因此,普通用户将无法更改 passwd
,因为授予所有用户直接访问此文件的权限太过危险。此问题的一种可行解决方法是使用 setuid 机制。setuid(设置的用户 ID)是一个特殊文件属性,它指示系统执行相应标记在特定用户 ID 下的程序。以 passwd
命令为例:
-rwsr-xr-x 1 root shadow 80036 2004-10-02 11:08 /usr/bin/passwd
您可以看见 s
,它表示为用户许可设置了 setuid 位。通过设置 setuid 位,启动 passwd
命令的所有用户都以 root
身份执行该命令。
19.1.2 setgid 位 #
setuid 位适用于用户。而对组而言也有一个等价的属性:setgid 位。设置了此位的程序基于保存该程序的组 ID 运行,而不论是哪个用户启动了该程序。因此,在设置了 setgid 位的目录中,所有新建文件和子目录都被指派到该目录所属的组。请考虑下面的示例目录:
drwxrws--- 2 tux archive 48 Nov 19 17:12 backup
您可以看见 s
,它表示为组许可设置了 setgid 位。目录的拥有者和 archive
组的成员可以访问此目录。不是该组成员的用户会“映射”到各自的组中。所有写入文件的有效组 ID 为 archive
。例如,使用组 ID archive
运行的备份程序即便没有 root 特权也能访问此目录。
19.1.3 粘性位 #
另外还可以设置粘滞位。属于可执行程序的粘滞位和属于目录的粘滞位在作用上有所不同。如果属于某个程序,以这种方式标记的文件将被装入 RAM,而不必在每次使用时从硬盘读取。由于目前硬盘的速度已经足够快,此属性已经很少使用。如果为目录指派了此位,则可以防止用户删除彼此的文件。典型示例如 /tmp
目录和 /var/tmp
目录:
drwxrwxrwt 2 root root 1160 2002-11-19 17:15 /tmp
19.2 ACL 的优势 #
传统情况下,会为 Linux 系统上的每个文件对象定义三组权限。这三组权限包括用于每种类型用户(即文件拥有者、组和其它用户这三种用户)的读 (r
)、写 (w
) 和执行 (x
) 权限。此外,还可以设置设置用户 ID、设置组 ID 和粘滞位。这种简缩概念完全适用于大多数实际情况。但对于较复杂的方案或高级应用程序,以前系统管理员需要采用多种变通方案来避开传统权限概念的限制。
可以将 ACL 作为传统文件权限概念的扩展来使用。它们可用于向单个用户或组指派权限,即使这些权限并不与原始拥有者或所属组相对应。访问控制列表是 Linux 内核的一项功能,目前受 Ext2、Ext3、Ext4、JFS 和 XFS 的支持。通过使用 ACL,无需在应用程序级别实施复杂的权限模型就可以实现复杂的方案。
如果您想用 Linux 服务器代替 Windows 服务器,则 ACL 的优势尤为明显。一些已连接的工作站即使在迁移后也仍可继续在 Windows 下运行。Linux 系统利用 Samba 向 Windows 客户端提供文件和打印服务。有了 Samba 支持访问控制列表,则既可以在 Linux 服务器上配置用户权限,也可以在具有图形用户界面的 Windows(仅限 Windows NT 和更高版本)中配置用户权限。利用 winbindd
(Samba 套件的一部分),甚至可以向仅存在于 Windows 域中而在 Linux 服务器中没有任何帐户的用户指派权限。
19.3 定义 #
- 用户类别
传统的 POSIX 许可权限概念使用三类用户在文件系统中指派权限:拥有者、拥有的组和其他用户。可以为每个用户类别设置三个权限位,用于分配读 (
r
)、写 (w
) 和执行 (x
) 权限。- ACL
所有种类的文件系统对象(文件和目录)的用户和组访问权限均通过 ACL 来确定。
- 默认 ACL
默认 ACL 只能应用于目录。它们确定文件系统对象在创建时从其父目录继承的权限。
- ACL 项
每个 ACL 都包含一组 ACL 项。ACL 项中包含一个类型、一个此项所关联的用户或组的限定符和一组权限。对于某些项类型,未定义组或用户的限定符。
19.4 处理 ACL #
表 19.1 “ACL 项类型”总结了 ACL 项 6 种可能出现的类型,每种类型都定义了一个用户或一组用户的权限。拥有者项定义了拥有该文件或目录的用户的权限。所属组项定义了文件所属组的权限。超级用户可以使用 chown
或 chgrp
更改拥有者或所属组,而在这种情况下,拥有者和所属组项表示新的拥有者和所属组。每个已命名用户项定义了在该项的限定符字段中指定的用户的权限。每个已命名组项定义了在该项的限定符字段中指定的组的权限。只有已命名用户和已命名组项具有非空的限定符字段。其他项定义了所有其他用户的权限。
通过定义这些项中的有效权限和要屏蔽的权限,掩码项进一步限制了已命名用户、已命名组和所属组项授予的权限。如果权限同时存在于上述项之一和掩码中,它们就是有效的。仅包含在掩码或实际项中的权限是无效的,表示未授予这些权限。拥有者和所属组项中定义的所有权限始终有效。表 19.2 “屏蔽访问权限”中的示例说明了这种机制。
有两种基本的 ACL 类:一种是最小 ACL,仅包含用于类型拥有者、所属组和其他的项,对应于文件和目录的传统权限位。另一种是扩展 ACL,它比前一种要复杂得多。它必须包含一个掩码项,并可能包含若干已命名用户和已命名组类型的项。
类型 |
文本形式 |
---|---|
拥有者 |
|
已命名用户 |
|
所属组 |
|
已命名组 |
|
掩码 |
|
其他 |
|
项类型 |
文本形式 |
许可权限 |
---|---|---|
已命名用户 |
|
|
掩码 |
|
|
有效权限: |
|
19.4.1 ACL 项和文件模式权限位 #
图 19.1 “最小 ACL:与权限位相比的 ACL 项”和图 19.2 “扩展 ACL:与权限位相比的 ACL 项”说明了最小 ACL 和扩展 ACL 这两种情况。这些图分为三块 — 左边一块显示 ACL 项的类型规范,中间一块显示一个示例 ACL,右边一块显示对应于传统权限概念的各个权限位(例如,如 ls
-l
所显示)。在这两种情况下,拥有者权限均被映射到 ACL 拥有者项。其他类别权限也被映射到各自的 ACL 项。但是,组类别权限的映射在这两种情况中是不同的。
对于最小 ACL(没有屏蔽),组类别许可权限被映射到 ACL 的所属组项。图 19.1 “最小 ACL:与权限位相比的 ACL 项”中显示了这一点。对于扩展 ACL(具有屏蔽),组类别许可权限被映射到屏蔽项。图 19.2 “扩展 ACL:与权限位相比的 ACL 项”中显示了这一点。
不管应用程序是否具有 ACL 支持,这种映射方式都可以确保应用程序的流畅交互。通过权限位方式分配的访问权限表示通过 ACL 所进行的所有其他“微调”的上限。对权限位的更改将由 ACL 反映出来,反之亦然。
19.4.2 具有 ACL 的目录 #
命令行上显示 getfacl
和 setfacl
的情况下,您可以访问 ACL。以下示例演示了这些命令的用法。
在创建目录之前,使用 umask
命令来定义每次创建文件对象时应屏蔽哪些访问权限。命令 umask
027
会设置以下默认权限:为拥有者授予全部权限 (0
)、拒绝组的写入访问权限 (2
),以及不为其他用户提供权限 (7
)。umask
实际上会屏蔽相应的许可权限位或将它们关闭。有关详细信息,请参考 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::---
输出的前三行显示了目录的名称、拥有者和所属组。随后三行包含三个 ACL 项,即拥有者、所属组和其他。事实上,对于最小 ACL,getfacl
命令不会生成您使用 ls
所不能获得的任何信息。
使用以下命令修改 ACL,为附加用户 geeko
和附加组 mascots
指派读、写和执行权限:
root #
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
显示的组类别权限位现在与 mask
项相对应。
drwxrwx---+ ... tux project3 ... mydir
输出的第一栏包含一个附加的 +
,表明此项存在一个扩展 ACL。
根据 ls
命令的输出,掩码项的权限包含写访问权限。传统情况下,这样的权限位意味着所属组(这里是 project3
)也具有对 mydir
目录的写访问权限。
但是,所属组的有效访问权限对应于为所属组和屏蔽定义的许可权限的重叠部分 — 在我们的示例中是 r-x
(参见表 19.2 “屏蔽访问权限”)。对本例中的所属组的有效权限而言,即使是在添加了 ACL 项之后,也未发生任何改变。
用 setfacl
或 chmod
编辑掩码项。例如,使用 chmod
g-w mydir
。ls
-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
来恢复原始权限。
19.4.3 具有默认 ACL 的目录 #
目录可以具有默认 ACL,这是一种特殊的 ACL,它定义的是此目录下的对象在创建时继承的访问权限。默认 ACL 影响子目录和文件。
19.4.3.1 默认 ACL 的效果 #
将目录的默认 ACL 的权限传递到文件和子目录时,有两种方式:
子目录会继承父目录的默认 ACL 作为其默认 ACL 和 ACL。
文件会继承该默认 ACL 作为其 ACL。
创建文件系统对象的所有系统调用都使用 mode
参数,该参数定义新创建的文件系统对象的访问权限。如果父目录没有默认 ACL,则从 mode
参数传递的权限中去除 umask
定义的权限位,同时将结果分配到新对象。如果父目录存在默认 ACL,则分配到新对象的权限位对应于 mode
参数的权限和默认 ACL 中定义的权限的重叠部分。这种情况下忽略了 umask
。
19.4.3.2 默认 ACL 的应用 #
以下三个示例说明了目录和默认 ACL 的主要操作:
将默认 ACL 添加到现有目录
mydir
,语句为:tux >
setfacl -d -m group:mascots:r-x mydirsetfacl
命令中的选项-d
提示setfacl
在默认 ACL 中执行以下修改(选项-m
)。仔细查看此命令的结果:
tux >
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,但为了创建有效的默认 ACL,setfacl
自动复制了 ACL 中的所有其他项。默认 ACL 对访问权限没有直接效果。它们只在创建文件系统对象时起作用。这些新对象只从其父目录的默认 ACL 中继承权限。在下一个示例中,我们将使用
mkdir
在mydir
中创建一个子目录,它将继承默认 ACL。tux >
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 也是相同的。使用
touch
在mydir
目录中创建一个文件,例如touch
mydir/myfile
。ls
-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
使用值为0666
的mode
,这意味所创建的新文件具有用于所有用户类别的读和写权限,前提是umask
或默认 ACL 中不存在任何其他限制(请参见第 19.4.3.1 节 “默认 ACL 的效果”)。实际上,这意味着mode
值中不包含的所有访问权限均将从各自的 ACL 项中去除。虽然没有从组类别的 ACL 项中去除任何权限,但仍修改了掩码项来屏蔽不在mode
中设置的权限。这种方式确保应用程序(如编译器)与 ACL 的交互平稳流畅。您可以创建具有有限访问权限的文件,然后将其标记为可执行文件。
mask
机制确保适当的用户和组可以在需要时执行它们。
19.4.4 ACL 检查算法 #
在为任何进程或应用程序授予访问受 ACL 保护的文件系统对象的权限之前,将应用检查算法。作为基本规则,按照以下序列检查 ACL 项:拥有者、命名用户、所属组或命名组以及其他组。访问将根据最适合进程的项进行处理。权限不能累加。
如果某个进程属于多个组并且潜在适合多个组项,情况会更为复杂。这时将从具有所需权限的合适项中随机选择一个。它与是哪些项触发了最终结果“已授权访问”无关。同样,如果没有任何适当组项包含所需的权限,则随机选择的项将触发最终结果“访问被拒绝”。
19.5 应用程序中的 ACL 支持 #
ACL 可用于实施非常复杂的权限方案以满足目前应用程序的要求。可以用一种智能方式将传统权限概念和 ACL 结合在一起。基本文件命令(cp
、mv
、ls
等)均支持 ACL,这与 Samba 和 Nautilus 相同。
Vi/Vim 和 emacs 都完全支持 ACL,它们会保留针对写入文件(包括备份)的权限。遗憾的是,许多编辑器和文件管理器仍缺少 ACL 支持。当用编辑器修改文件时,文件的 ACL 有时会被保留,有时则会丢失,这取决于所使用编辑器的备份方式。如果编辑器向原始文件写入更改,则会保留 ACL。如果编辑器将已更新的内容保存到一个新文件,然后将此文件重命名为旧文件名,则 ACL 可能会丢失,除非编辑器支持 ACL。除了 star
存档程序外,当前没有任何其他备份应用程序会保留 ACL。
19.6 更多信息 #
有关 ACL 的详细信息,请参见 getfacl(1)
、acl(5)
和 setfacl(1)
的手册页。