chmod 命令

作者:Eric Goebelbecker

您知道如何重命名您无法读取的文件吗?更进一步,您知道其他用户如何重命名您的文件吗?您是否曾经从另一台主机通过 ftp 下载程序,却无法运行它?

文件权限的主题,以及如何使用 chmod 命令来操作它们,是开始了解这些情况的好起点。

首先,让我们创建一个文件并检查它的长列表。(为了适应杂志版面,本文中的所有列表都经过修剪。)

$ touch test_file
$ ls -l test_file
-rw-rw-r--   1 eric     users

由于是我创建了这个文件,因此第三列显示我的用户名作为文件所有者,第四列显示我的用户组,这是有道理的。(在某些系统中,用户组名可能与用户名相同。)当您按照这些示例操作时,您将看到您的用户名代替 “eric”。

目录列表的最左列显示文件的 模式。模式是用于指代文件权限的术语。ls 将文件类型和模式一起显示为十个单字符字段的分组

类型

所有者

用户组

其他

-

rwx

rw-

r--

类型字段有几个有效值。为了本教程的目的,我们只关注两个:空 (-) 表示普通文件,d 表示目录。

其他三列涵盖了三种 类别 的访问权限,这些权限存储在类 Unix 文件系统中的每个文件中。Linux(和 Unix)根据用户所有权、用户组所有权和其他(或世界)来评估访问权限。

对于这些类别中的每一个,权限都根据三种 操作 进行评估:读取 (r)、写入 (w) 和执行 (x)。上面的权限指定了所有者的“完全”访问权限,用户组的读取和写入权限,以及其他用户的仅读取权限(一种不寻常的组合,用于演示)。这些权限指定了

  • 文件的所有者被允许读取、写入和执行该文件。

  • 任何属于拥有该文件的用户组的成员的用户都被允许写入该文件。

  • 任何其他用户只能读取该文件。

更改权限

如果 test_file 是一个非常重要的文档,我们不希望任何人能够修改或删除它,我们需要从用户组中删除写入权限

$ chmod g-w test_file
$ ls -l test_file
-rw-r--r--   1 eric     users

我们看到用户组的 w 现在被 - 替换,表示用户组 users 的成员被拒绝写入权限。

如果 test_file 包含敏感信息,只有用户组 users 的成员才能查看

$ chmod o-r test_file
$ ls -l test_file
-rw-r-----   1 eric     users

现在我们看到模式字段的最后三元组,它指定了其他用户的权限,都是短划线。这意味着不属于 users 组的其他用户没有任何权限对 test_file 执行任何操作。

chmod 模式的命令行用法如下所示

chmod [options] new-mode filename

新模式以 八进制模式符号模式 指定。我们将首先介绍符号模式。在第一个示例中,我们使用 g-w 删除用户组的写入权限。您可能可以猜到,g 代表用户组,- 代表删除,w 代表写入权限。

$ chmod g+wx test_file
$ ls -l test_file
-rw-rwx---   1 eric     users

此操作为用户组添加了写入和执行权限。

让我们看一个这些权限在实际操作中的示例。

$ chmod u-rwx test_file
$ ls -l test_file
----rwx---   1 eric     users
$ cat test_file
cat: test_file: Permission denied
$ cat .profile > test_file
bash: test_file: Permission denied

我们无法显示文件的内容,因为我们没有读取自己文件的权限。当我们指定 u-rwx 给 chmod 时,我们删除了用户(文件所有者)的所有访问权限。当我们尝试将另一个文件的内容添加到其中时,我们也遭到拒绝,因为我们删除了写入权限。(我应该注意,rm 仍然能够删除此文件,尽管它通常会请求确认。)

$ chmod u+rwx test_file
$ ls -l test_file
-rwxrwx---   1 eric     users

当我们指定 u+rwx 时,所有权限都会恢复。从我们拥有的文件中删除权限不会影响我们恢复权限的能力,因为模式 存储在文件中。它存储在称为 inode 条目的结构中。只有文件所有者(和 root 用户)可以修改它。

了解 chmod

让我们看一下 chmod 选项的摘要,然后深入介绍每个选项

用户

u 用户(所有者)

g 用户组

o 其他(世界)

a 所有(用户、用户组和其他)

操作

+ 添加

- 删除

= 精确设置

模式

r 读取

w 写入

x 执行

X 有条件地设置执行

s 设置 UID 或设置 GID

t 设置“粘滞位”

$ chmod a+rwx test_file
$ ls -l test_file
-rwxrwxrwx   1 eric     users

这演示了在使用符号模式时,用户的第四个可能的符号。我们使用 a 一次为所有用户类别设置完全权限。让我们删除该文件并重新开始,以演示 = 运算符与 +- 运算符之间的区别。(从现在开始,我们将假设您知道如何获取目录列表,并且不会列出 ls 命令。)

$ rm test_file
$ touch test_file
-rw-rw-r--   1 eric     users
$ chmod g+x test_file
-rw-rwxr--   1 eric     users

这为用户组添加了执行权限。

$ chmod g=x test_file
-rw---xr--   1 eric     users

= 运算符将用户组的权限设置为执行,这样做删除了读取和写入权限。虽然 +- 设置或取消设置指定的权限,但 =精确地 设置指定的模式,并删除任何其他模式。

当引用文件时,读取、写入和执行模式非常直接。读取和写入允许用户分别检查和修改/删除文件中的数据。执行允许用户执行 shell 脚本或二进制程序。如果您从一台主机通过 ftp 下载程序到另一台主机,然后尝试在不设置执行权限的情况下运行它,它将失败,因为 ftp 不会设置执行权限。

目录

对于目录,规则可能稍微复杂一些。

读取权限允许用户检查目录的内容。

$ mkdir test_dir
$ touch test_dir/foo
$ ls test_dir
foo
$ chmod u-r test_dir
$ ls test_dir
ls: test_dir: Permission denied

写入权限允许用户修改 目录的内容。这意味着,如果文件权限允许,目录上缺少写入权限不会阻止用户修改目录中的文件。它 确实 会阻止用户重命名、移动、删除或创建目录中的任何文件。这是因为目录实际上是一个文件,其中包含文件名列表,因此读取和写入权限控制对该列表的访问。

$ chmod u=rx test_dir
dr-xrwxr-x   2 eric     users
$ touch test_dir/bar
touch: test_dir/bar: Permission denied
$ mv test_dir/foo ./foo
mv: cannot move `test_dir/foo' to `./foo':
Permission denied

此属性也以另一种方式起作用。由于写入权限允许修改目录条目,因此用户可以移动或重命名文件,而无需权限检查内容。这是关注重要目录的写入权限的一个非常好的理由。

为了演示

$ ls -l test_dir
-rw-rw-r--   2 eric  users  foo
$ chmod u=rwx test_dir
$ chmod u=rx test_dir/foo
$ cat .bashrc > test_dir/foo
bash: test_dir/foo: Permission denied
$ mv test_dir/foo ./foo
$ ls test_dir
(It's empty)
$ ls foo
foo (It's in our present directory.)

目录的执行权限(也称为搜索权限)也非常重要。执行权限对于 访问 目录是必要的。

$ chmod u=rwx test_dir
$ cp ~/.bashrc test_dir
(any text file will do)
$ chmod u=rw test_dir
$ cd test_dir
bash: test_dir: Permission denied
$ cat test_dir/.bashrc
cat: test_dir/.bashrc: Permission denied

此 .bashrc 副本对我们没有太大用处。但是,为目录设置执行权限而不设置读取或写入权限可能会派上用场。

$ chmod u=x test_dir
$ cat test_dir/.bashrc
(we see the contents of the file)
$ ls test_dir
ls: test_dir: Permission denied

仅具有执行权限的目录可用于“隐藏”文件。只有知道确切文件名和路径的用户才能访问它们;这包括数据文件和程序。

条件执行

让我们回到 test_file 来检查 X 选项。

$ chmod u=rw,g=r,o=r test_file
-rw-r--r--   1 eric     users
$ chmod o+X test_file
-rw-r--r--   1 eric     users
$ chmod u+x test_file
-rwxr--r--   1 eric     users
$ chmod o+X test_file
-rwxr--r-x   1 eric     users

在第一个命令中,我们看到可以通过使用逗号分隔模式规范,一次为多个类别设置选项。在这里,我们设置模式,以便任何用户都没有执行权限。在第二个命令中,我们尝试使用 X 为其他用户设置执行权限。这失败了,因为 X 仅在其中一个类别已经具有执行权限时才起作用。当我们为所有者添加执行权限时,X 为其他用户设置了执行权限。

s 选项设置或删除设置 UID (SUID) 和设置 GID (SGID) 模式。这些模式在 UNIX/Linux 安全性方面非常重要。当文件设置了 SUID 模式时,执行它的进程在程序执行期间具有文件所有者的有效权限。

例如,程序 dip 用于创建 SLIP 网络连接。这需要 root 访问权限,因为创建网络接口设备需要 root 访问权限。dip 程序可以属于 root 用户并设置 SUID 模式,而不是强迫用户成为 root 用户才能使用 dip,这将需要用户知道 root 密码。

$ ls -l /usr/sbin/dip
-r-s--x---   1 root     dip

用户执行字段中的 s 表示已设置 SUID 模式。SUID 模式的另一个用途示例是 passwd 程序,它允许用户修改 passwd(或 shadow)文件。

出于安全原因,SUID 位只能影响二进制程序;它对 Linux 中的 shell 脚本没有影响。

SGID 模式设置用户组而不是所有者,并使用(例如)g+s 设置。它还有另一个用途。

当用户创建新文件时,用户组所有权默认为用户的默认用户组,该用户组在 passwd 文件中列出。有时用户属于多个用户组,并且想要共享文件。SGID 模式可以为此提供一种方便的方法。如果为目录设置了 SGID 模式位,则在该目录中创建的新文件将属于该用户组,而与创建者的默认用户组无关。如果您属于多个用户组,请尝试这样做。(您可以使用 id 命令检查您属于哪些用户组。默认用户组列在最前面,您可以使用 chgrp 命令将文件的用户组所有权更改为您所属的另一个用户组。)

$ mkdir test_dir
$ chgrp nondefault test_dir
$ chmod g+s test_dir
$ touch test_dir/foo
$ ls -l test_dir/foo
-rw-rw-r--   1 eric     nondefault

SUID 和 SGID 模式可能是一个安全漏洞。但是,当谨慎使用时,它们是非常有价值的工具,实际上通过提供重要密码的替代方案来增强系统安全性。

使其简单化

指定用户类别可用于简化复制权限。

$ chmod g=u test_file
-rwxrwxr-x   1 eric     users

这会将权限从用户复制到用户组。所有类别都可以在 +-= 运算符的右侧以这种方式使用。

$ chmod o-u test_file
-rwxrwx---   1 eric     users

这将清除其他用户拥有的用户的所有权限。

上面列出的最后一个模式是 t 选项,称为“粘滞位”。此模式实际上在命令行上受支持,以便与来自较旧操作系统的 shell 脚本兼容。Linux 不需要它。如果安装指南指示您使用它,它实际上什么也不做。

做你的数学题

文件访问模式也可以使用八进制表示法设置。此语法是通过将模式字段相加构建的。对于每个用户类别,字段的计算方式如下

  • 4 读取

  • 2 写入

  • 1 执行

任何类别的完全权限都将是 7,没有权限将是 0

$ chmod 754 test_file
-rwxr-xr-x   1 eric     users

类别以 ls 显示它们的相同顺序传递给 chmod。我们设置的模式按以下方式分解

      Owner = 4 + 2 + 1 = 7
      Group = 4 + 1     = 5
      World = 4         = 4

八进制模式很方便,因为其他实用程序(如 find)期望以这种方式表示模式。

在八进制模式下,SUID 和 SGID 通过在用户模式 之前 的另一列中指定它们来设置。对于 SUID 使用 4,对于 SGID 使用 2,对于两者都使用 6

$ chmod 4755 test_file
-rwsr-xr-x   1 eric     users
强大的 chmod

Chmod 还提供了一些命令行选项来简化管理任务。对于在目录树中更改文件权限,请使用 -R

$ chmod -R g-w test_dir

这将删除 test_dir 及其下所有文件中用户组的写入权限。

为了控制来自 chmod 的消息输出,请使用 -c-v-f

$ chmod -v 700 test_file
mode of test_file changed to 0700 (rwx------)

此选项使 chmod 显示 test_file 的权限是如何设置的。-c 选项使 chmod 仅在文件更改时显示消息,-f 选项抑制有关无法更改的文件的消息。

Chmod 还提供了 --version 选项来显示版本,以及 --help 来查看简短的帮助消息。

总结

文件权限是 Linux 的组成部分。相同的概念也适用于其他操作系统对象,例如信号量、共享内存和 NIS+。本教程为您提供了一些保护数据和更好地享受 Linux 系统的基本知识,并为您学习更多关于 Linux 的知识提供了精神基础。

Eric Goebelbecker (eric@cnct.com) 是路透社美国公司 (Reuters America, Inc.) 的系统分析师。他为使用市场数据检索和操作 API 的交易室和后台运营部门的客户(主要是金融机构)提供支持。在他的业余时间(每周约 15 分钟...),他阅读哲学并研究 Linux。

加载 Disqus 评论