第九章:权限

Unix传统中的操作系统与MS-DOS传统中的不同之处在于,它们不仅是多任务(multitasking)系统,也是多用户(multi-user)系统。

这到底意味着什么?这意味着不止一个人可以同时使用电脑。虽然一台典型的电脑可能只有一个键盘和显示器,但它仍然可以被多个用户使用。例如,如果计算机连接到网络或互联网,远程用户可以通过 ssh (secure shell,安全外壳)登录并操作计算机。事实上,远程用户可以执行图形应用程序,并在远程显示器上显示图形输出。

Linux的多用户功能不是最近的“创新”(innovation),而是深深嵌入操作系统设计中的一项功能。考虑到Unix创建的环境,这是完全有道理的。多年前,在计算机“个人化”之前,它们是大型、昂贵和集中的(centralized)。例如,一个典型的大学计算机系统由位于一栋建筑内的大型中央计算机和位于整个校园内的终端组成,每个终端都连接到大型中央计算机。这台电脑可以同时支持许多用户。

为了实现这一点,必须设计一种方法来保护用户免受彼此的伤害。毕竟,不能允许一个用户的操作导致计算机崩溃,也不能允许一个人干扰属于另一个用户。

在本章中,我们将研究系统安全的这一重要部分,并介绍以下命令:

第九章:权限用户,组成员,和其他所有人读,写,和运行chmod —— 更改文件模式Octal到底是什么?使用GUI设置文件模式umask —— 设置默认权限一些特殊权限改变身份su —— 使用替代用户和组ID运行Shellsudo —— 以其他用户身份执行命令现代Linux发行版和 sudochown —— 更改文件所有者和群组chgrp —— 更改组所有权行使我们的特权更改你的密码总结

用户,组成员,和其他所有人

当我们在第3章中探索系统时,我们在尝试检查 /etc/shadow 等文件时可能遇到了一个问题:

出现此错误消息的原因是,作为普通(regular)用户,我们没有读取此文件的权限。

在Unix安全模型中,用户可以拥有(own)文件和目录。当用户拥有文件或目录时,用户可以控制其访问权限。反过来,用户可以属于一个由一个或多个用户组成的组(group),这些用户由其所有者授予访问文件和目录的权限。除了授予对组的访问权限外,所有者还可以向每个人(ererybody)授予一组访问权限,这些权限称为其他人(others ,有时称为 world ,世界)。要查找有关我们身份的信息,我们使用 id 命令:

让我们看看输出。创建用户帐户时,会为用户分配一个称为 user IDuid)的数字,然后为了人类的利益(the sake of humans),该数字会映射到用户名。用户被分配了一个主组ID(primary group IDgid),并且可能属于其他组。上面的例子来自Fedora系统。在其他系统上,如Ubuntu,输出可能看起来有点不同:

正如我们所看到的,uid和gid数字是不同的。这仅仅是因为Fedora的常规用户帐户编号从500开始,而Ubuntu从1000开始。我们还可以看到Ubuntu用户属于更多的组。这与Ubuntu管理系统设备和服务权限(privileges)的方式有关。

那么,这些信息是从哪里来的呢?就像Linux中的许多东西一样,它来自几个文本文件。用户帐户在 /etc/passwd 文件中定义,组在 /etc/group 文件中定义。创建用户帐户和组时,这些文件会与 /etc/shadow 一起修改, /etc/shadows 包含有关用户密码的信息。对于每个用户帐户, /etc/passwd 文件定义了用户(登录)名、uid、gid、用户的真实姓名、主目录和登录shell。如果我们检查 /etc/passwd/etc/group 的内容,我们会注意到,除了常规用户帐户外,还有超级用户(始终为uid 0)和各种其他系统用户的帐户。

在下一章中,当我们介绍流程时,我们将看到其中一些其他“用户”实际上非常忙。

虽然许多类Unix系统将常规用户分配给一个共同的组,如“users”,但现代Linux的做法是创建一个与用户同名的唯一单成员组。这使得某些类型的权限分配更容易。

读,写,和运行

文件和目录的访问权限根据读取访问、写入访问和执行访问来定义。如果我们查看 ls 命令的输出,我们可以得到一些关于如何实现它的线索:

列表的前10个字符是文件属性。第一个字符是文件类型。下表描述了我们最有可能看到的文件类型(还有其他不太常见的类型):

属性文件类型
-常规文件
d目录
l符号链接。请注意,对于符号链接,其余的文件属性始终是“rwxrwxrwx”,并且是虚拟值。真正的文件属性是符号链接指向的文件的属性。
c字符特殊文件(character special file)。
此文件类型是指将数据作为字节流处理的设备,例如终端或 /dev/null
b块特殊文件(block special file)。
此文件类型是指以块形式处理数据的设备,如硬盘或DVD驱动器。

文件属性的其余九个字符称为文件模式(file mode),表示文件的所有者、文件的组所有者和其他所有人的读取、写入和执行权限。

UserGroupOther
rwxrwxrwx

下表描述了 rwx 模式属性对文件和目录的影响:

属性文件目录
r允许打开和读取文件。允许列出目录的内容,但除非还设置了execute属性,否则没有可用的文件信息。
w允许写入或截断文件,但此属性不允许重命名或删除文件。
删除或重命名文件的能力由目录属性决定。
如果还设置了execute属性,则允许创建、删除和重命名目录中的文件。
x允许将文件视为程序并执行。
用脚本语言编写的程序文件也必须设置为可读才能执行。
允许进入目录(即 cd directory)和访问目录元数据(即 ls -l directory)。
cprmmv 等文件操作需要访问该目录。

下表提供了文件属性设置的一些示例:

文件属性含义
-rwx------一个可由文件所有者读取、写入和执行的常规文件。没有其他人可以访问。
-rw-------文件所有者可读写的常规文件。没有其他人可以访问。
-rw-r--r--文件所有者可读写的常规文件。文件所有者组的成员可以读取该文件。该文件可供他人阅读。
-rwxr-xr-x一个可由文件所有者读取、写入和执行的常规文件。其他人可以读取并执行该文件。
-rw-rw----仅由文件所有者和文件组所有者成员可读写的常规文件。
lrwxrwxrwx符号链接。所有符号链接都具有“虚拟”权限。真正的权限保存在符号链接指向的实际文件中。
drwxrwx---一个目录。所有者和所有者组的成员可以进入目录,并在目录中创建、重命名和删除文件。
drwxr-x---一个目录。所有者可以进入目录并在目录中创建、重命名和删除文件。所有者组的成员可以进入目录,但不能创建、删除或重命名文件。

chmod —— 更改文件模式

要更改文件或目录的模式(permissions,权限),可以使用 chmod 命令。请注意,只有文件的所有者或超级用户可以更改文件或目录的模式。 chmod 支持两种不同的方式来指定模式更改:八进制(octal)数字表示或符号表示。我们将首先介绍八进制数表示法。

Octal到底是什么?

octal (八进制,base 8),和它的表亲,hexadecimal (十六进制,base 16)是常用于计算机上表示数字的数字系统。我们人类,由于我们(或至少我们大多数人)天生有10个手指,所以使用以10为基数的数字系统进行计数。另一方面,计算机天生只有一根手指,因此所有的计数都是 binary(二进制,base 2)。他们的数字系统只有两个数字,0和1。所以,在二进制中,计数看起来像这样:

0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011...

在八进制中,计数是用数字0到7完成的,如下所示:

0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21...

十六进制计数使用数字0到9加上字母“A”到“F”:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13...

虽然我们可以看到二进制的意义(因为计算机只有一个手指),但八进制和十六进制有什么好处?答案与人类的便利性有关。很多时候,小部分数据在计算机上表示为位模式(bit patterns)。以RGB颜色为例。在大多数计算机显示器上,每个像素由三个颜色分量组成:八位红色、八位绿色和八位蓝色。可爱的中蓝色是一个24位数字:

010000110110111111001101

你想整天读写这些数字吗?我不这么认为。这是另一个数字系统会有所帮助的地方。十六进制数中的每个数字表示二进制中的四个数字。在八进制中,每个数字代表三个二进制数字。因此,我们的24位中蓝色可以压缩为6位十六进制数:

436FCD

由于十六进制数中的数字与二进制数中的位“对齐”(line up),我们可以看到我们颜色的红色分量是43,绿色6F和蓝色CD。

如今,十六进制表示法(通常称为“hex”)比八进制更常见,但正如我们很快就会看到的,八进制表示三位二进制的能力将非常有用...

使用八进制表示法,我们使用八进制数字来设置所需权限的模式。由于八进制数中的每个数字代表三个二进制数字,因此这很好地映射到用于存储文件模式的方案。下表显示了我们的意思:

八进制二进制文件模式
0000---
1001--x
2010-w-
3011-wx
4100r--
5101r-x
6110rw-
7111rwx

通过使用三个八进制数字,我们可以为所有者、组所有者和世界设置文件模式。

通过传递参数 600 ,我们能够设置所有者的读写权限,同时删除组所有者和其他人的所有权限。虽然记住八进制到二进制的映射可能看起来不方便,但我们通常只需要使用几个常见的映射:7(rwx)、6(rw-)、5(r-x)、4(r--)和0(---)。

chmod 还支持用于指定文件模式的符号表示法。符号表示法分为三个部分。

为了指定受影响的人,使用了字符“u”、“g”、“o”和“a”的组合,如下表所示:

符号含义
u“user”的缩写,即文件或目录的所有者。
g组所有者。
oother的缩写。
aall的缩写。这是 “u”、“g” 和 “o” 的组合

如果没有指定字符,则假定为 all 。该操作可以是 + 表示要添加权限, - 表示要删除权限,或 = 表示只应用指定的权限,删除所有其他权限

权限由 rwx 字符指定。下表提供了一些符号表示法的示例:

符号含义
u+x为所有者添加执行权限。
u-x移除所有者的执行权限。
+x为用户、组和其他人添加执行权限。这相当于 a+x。
o-rw移除其他人的读写权限。
go=rw将组所有者和除用户之外的任何人设置为具有读写权限。
如果组所有者或其他人以前具有执行权限,则会将其删除。
u+x,go=rx为用户添加执行权限,并设置组和其他人的读取和执行权限。
多个规范可以用逗号分隔。

有些人更喜欢使用八进制表示法,有些人真的很喜欢符号表示法。符号表示法确实提供了允许我们在不干扰任何其他属性的情况下设置单个属性的优点。

查看 chmod 手册页以了解更多详细信息和选项列表。关于 --recursive (递归)选项,有一点需要注意:它同时作用于文件和目录,因此它并不像我们希望的那样有用,因为我们很少希望文件和目录具有相同的权限。

使用GUI设置文件模式

现在我们已经了解了如何设置文件和目录的权限,我们可以更好地理解GUI中的权限对话框。在 Files(GNOME)和 Dolphin(KDE)中,右键单击文件或目录图标将显示一个属性对话框。以下是GNOME的一个示例:

GNOMEfilepermissionsdialog

在这里,我们可以看到所有者、组和其他人的设置。

umask —— 设置默认权限

umask 命令控制创建文件时赋予文件的默认权限。它使用八进制表示法来表示要从文件的模式属性中删除的位掩码mask)。让我们来看看。

我们首先删除了 foo.txt 的任何旧副本,以确保我们重新开始。接下来,我们运行不带参数的 umask 命令来查看当前值。它的响应值为 0002 (值 0022 是另一个常见的默认值),这是我们掩码的八进制表示。接下来,我们创建一个新的 foo.txt 文件实例,并观察其权限。

我们可以看到,用户和组都获得了读写权限,而其他人只获得了读权限。世界没有写权限的原因是掩码的值。让我们重复一下我们的例子,这次我们自己设置掩码(mask):

当我们将掩码设置为 0000 (有效地将其关闭)时,我们看到该文件现在是全球可写的。为了理解这是如何工作的,我们必须再次研究八进制数。如果我们将掩码更改为 0002 ,将其展开为二进制,然后将其与属性进行比较,我们可以看到会发生什么。

类型结果
原始文件模式--- rw- rw- rw-
掩码000 000 000 010
结果--- rw- rw- r--

暂时忽略前导零(我们将在一分钟内找到),并观察到在掩码中出现1的地方,一个属性被删除了——在这种情况下,是世界写入权限。这就是掩码的作用。掩码的二进制值中出现1的任何地方,都表示属性未设置。如果我们查看掩码值0022,我们可以看到它的作用。

类型结果
原始文件模式--- rw- rw- rw-
掩码000 000 010 010
结果--- rw- r-- r--

同样,如果二进制值中出现1,则相应的属性未设置。使用一些值(尝试一些七)来习惯它的工作原理。完成后,记得清理干净。

大多数时候,我们不必换掩码;发行版提供的默认值将很好。然而,在一些高度安全的情况下,我们会想要控制它。

一些特殊权限

虽然我们通常看到八进制权限掩码表示为三位数,但用四位数表示在技术上更正确。为什么?因为,除了读取、写入和执行权限外,还有一些其他较少使用的权限设置。

以下是一些使用chmod和符号表示法设置这些特殊权限的示例。下面是一个将setuid分配给程序的示例:

chmod u+s program

下面是将setgid分配给目录的示例:

chmod g+s dir

最后,这里有一个将sticky位分配给目录的示例:

chmod +t dir

查看 ls 的输出时,可以确定特殊权限。这里有一些例子。

首先,一个具有 setuid 属性的程序示例:

-rwsr-xr-x

下面是一个具有 setgid 属性的目录示例:

drwxrwsr-x

下面是一个设置了 sticky 位的目录示例:

drwxrwxrwt

改变身份

有时我们可能会发现有必要使用另一个用户的身份。我们通常希望获得超级用户权限来执行一些管理任务,但也有可能“成为”另一个常规用户,例如测试帐户。有三种方式可以获得另一种身份。

我们将跳过第一种技术,因为我们知道如何做到这一点,而且它缺乏其他两种技术的便利性。在我们自己的shell会话中, su 命令允许我们假设另一个用户的身份,并使用该用户的ID启动新的shell会话,或者以该用户的身份发出单个命令。 sudo 命令允许管理员设置一个名为 /etc/sudoers 的配置文件,并定义允许特定用户在假定身份下执行的特定命令。使用哪个命令的选择在很大程度上取决于您使用的Linux发行版。您的发行版可能包含这两个命令,但其配置将偏向其中一个。我们将从 su 开始。不过要知道, su 的使用在现代Linux发行版中已经不受欢迎了。

su —— 使用替代用户和组ID运行Shell

substitute user —— 替代用户

su命令用于以其他用户身份启动shell。命令语法如下:

su [-[l]] [user]

如果包含 -l 选项,则生成的shell会话是指定用户的登录shell(login shell)。这意味着用户的环境已加载,工作目录已更改为用户的主目录。这通常是我们想要的。如果未指定用户,则假定为超级用户。请注意(奇怪的是) -l 可以缩写为 - ,这是它最常用的用法。假设root帐户设置了密码(这在现代发行版中不是自定义的),我们可以这样为超级用户启动一个shell:

输入命令后,系统会提示我们输入超级用户的密码。如果输入成功,将出现一个新的shell提示符,指示此shell具有超级用户权限(尾随的 # 而不是 $ ),当前工作目录现在是超级用户的主目录(通常为 /root )。一旦进入新的shell,我们就可以以超级用户的身份执行命令。完成后,输入 exit 返回上一个shell。

也可以通过这种方式使用 su 来执行单个命令,而不是启动新的交互式命令。

su -c 'command'

使用此表单,将单个命令行传递给新shell执行。将命令括在引号中很重要,因为我们不希望扩展发生在我们的shell中,而是发生在新的shell中。

sudo —— 以其他用户身份执行命令

sudo 命令在许多方面类似于 su ,但具有一些重要的附加功能。管理员可以配置 sudo ,允许普通用户以受控方式以不同用户(通常是超级用户)的身份执行命令。特别地,用户可能被限制为一个或多个特定命令,而没有其他命令。另一个重要区别是使用 sudo 不需要访问超级用户的密码。使用 sudo 进行身份验证需要用户自己的密码。例如,假设 sudo 已配置为允许我们运行一个名为 backup_script 的虚构备份程序,该程序需要超级用户权限。使用 sudo 可以这样做:

输入命令后,系统会提示我们输入密码(不是超级用户的密码),一旦身份验证完成,就会执行指定的命令。 susudo 之间的一个重要区别是 sudo 不会启动新的shell,也不会加载其他用户的环境。这意味着命令的引用方式不需要与不使用 sudo 时不同。请注意,可以通过指定各种选项来覆盖此行为。请注意,通过使用 -i 选项,可以使用 sudo 启动交互式超级用户会话(很像 su - )。有关详细信息,请参阅 sudo 手册页。

要查看 sudo 授予的权限,请使用 -l 选项列出它们:

现代Linux发行版和 sudo

对于普通用户来说,一个经常出现的问题是如何执行需要超级用户权限的某些任务。这些任务包括安装和更新软件、编辑系统配置文件以及访问设备。在Windows世界中,这通常是通过授予用户管理权限来实现的。这允许用户执行这些任务。然而,它也使用户执行的程序具有相同的能力。在大多数情况下,这是可取的,但它也允许病毒等恶意软件自由控制计算机。

在Unix世界中,由于Unix的多用户传统,普通用户和管理员之间一直存在较大的分歧。Unix中采用的方法是只在需要时授予超级用户权限。为此,通常使用 susudo 命令。

多年前,大多数Linux发行版都依赖 su 来实现这一目的。su 不需要 sudo 所需的配置,在Unix中拥有root帐户是传统做法。然而,这带来了一个问题。用户不必要地试图以root身份操作。事实上,一些用户仅以root用户身份操作他们的系统,因为它消除了所有恼人的“permission denied”消息。这就是将Linux系统的安全性降低到Windows系统的方法。这不是个好主意。

当Ubuntu推出时,它的创建者采取了不同的策略。默认情况下,Ubuntu禁止登录root帐户(因为没有为帐户设置密码),而是使用 sudo 授予超级用户权限。初始用户帐户通过 sudo 被授予超级用户权限的完全访问权限,并可能向后续用户帐户授予类似的权限。这种授予特权的方法现在是大多数现代发行版公认的标准。

chown —— 更改文件所有者和群组

chown 命令用于更改文件或目录的所有者和组所有者。使用此命令需要超级用户权限。 chown 的语法如下:

chown [owner] [:[group]] file ...

chown 可以根据命令的第一个参数更改文件所有者和/或文件组所有者。下表提供了一些示例:

参数结果
bob将文件的所有权从当前所有者更改为用户 bob
bob:users将文件的所有权从其当前所有者更改为用户 bob ,并将文件组所有者更改为组 users
:admins将组所有者更改为组 admins 。文件所有者不变。
bob:将文件所有者从当前所有者更改为用户 bob ,并将组所有者更改为用户名 bob 的登录组。

假设我们有两个用户;janet 有超级用户权限,tony 没有。用户 janet 希望将一个文件从她的主目录复制到用户 tony 的主目录。由于用户 janet 希望 tony 能够编辑文件, janet 将复制文件的所有权从 janet 更改为 tony

在这里,我们看到用户 janet 将文件从她的目录复制到用户 tony 的主目录。接下来, janet 将文件的所有权从 root (使用sudo的结果)更改为 tony 。在第一个参数中使用尾随冒号, janet 还将文件的组所有权更改为 tony 的登录组,该组恰好是 tony 组。

请注意,在第一次使用 sudo 后,没有提示 janet 输入密码。这是因为在大多数配置中, sudo “信任”我们几分钟,直到它的计时器用完。

chgrp —— 更改组所有权

在旧版本的Unix中, chown 命令只更改了文件所有权,而不是组所有权。为此,使用了单独的命令 chgrp 。它的工作方式与 chown 基本相同,只是限制更多。

行使我们的特权

现在我们已经了解了权限的工作原理,是时候展示一下了。我们将演示一个常见问题的解决方案——设置共享目录。让我们重温一下我们的朋友 janettony 。他们都有音乐收藏,并希望建立一个共享目录,在那里他们将各自的音乐文件存储为 Ogg VorbisMP3 。和以前一样,用户 janet 可以通过 sudo 访问超级用户权限。

需要创建一个组,让 janettony 都成为成员。这分两步完成。首先,使用 groupadd 命令,我们创建组,然后使用 usermod 命令将用户添加到组中:

usermod 命令一起使用的选项是 -a--append 的缩写)和 -G--group 的缩写),它们将指定的用户添加到 /etc/group 文件中的相应组中。

接下来,janet 创建音乐文件的目录。

由于 janet 正在操作其主目录之外的文件,因此需要超级用户权限。创建目录后,它具有以下所有权和权限:

正如我们所看到的,该目录由 root 拥有,权限模式为 755 。为了使此目录可共享, janet 需要更改组所有权和组权限以允许写入。

使用 chown 命令,janet 将目录的组所有者设置为 music ,然后使用 chmod 将目录权限设置为 2755 。这将设置 setguid ,使目录中的所有文件继承与目录相同的组所有权。我们通过执行 chmod 2755 来实现这一点,但我们也可以通过使用 chmod g+s 的符号方法来实现。

这一切意味着什么?这意味着我们现在有一个目录 /usr/local/share/Music ,由 root 拥有,允许对组 music 进行读写访问。组 music 有成员 janettony ;因此,janettony 可以在 /usr/local/share/Music 目录下创建文件。其他用户可以列出目录的内容,但不能在那里创建文件。

但我们仍然有一个问题。此系统上的默认 umask0022 ,它阻止组成员写入属于组其他成员的文件。如果共享目录仅包含文件,这将不是问题,但由于此目录将存储音乐,并且音乐通常按艺术家和专辑的层次结构组织,因此组的成员需要能够在其他成员创建的目录中创建文件和目录。我们需要将 janettony 使用的 umask 改为 0002

janet 将她的 umask 设置为 0002 ,并创建一个新的测试文件和目录:

现在,文件和目录都以正确的权限创建,允许组 music 的所有成员在 Music 目录中创建文件和目录。

剩下的一个问题是 umask 。必要的设置仅持续到会话结束,必须重置。在第11章中,我们将探讨如何将 umask 更改为永久性。

更改你的密码

本章中我们将讨论的最后一个主题是为自己设置密码(如果我们有超级用户权限,也为其他用户设置密码)。要设置或更改密码,请使用 passwd 命令。命令语法如下:

passwd [user]

要更改密码,我们只需输入 passwd 命令。系统将提示我们输入旧密码和新密码。

passwd命令将尝试强制使用“强”密码。这意味着它将拒绝接受太短、与以前的密码太相似、是字典单词或太容易猜到的密码。

如果我们有超级用户权限,您可以将用户名指定为 passwd 命令的参数,为其他用户设置密码。超级用户还可以使用其他选项来允许帐户锁定、密码过期等。有关详细信息,请参阅 passwd 手册页。

passwdaddgroupusermod 命令是 shadow-utils 包中一组命令的一部分。下表列出了该包中包含的一些命令:

命令说明
lastlog报告所有用户或给定用户的最新登录。
useradd创建新用户或更新默认新用户信息。
userdel删除用户帐户和相关文件。
usermod修改用户帐户。
groupadd创建一个新组。
groupdel删除一个组。
groupmod修改系统上的组定义。

我们不会详细介绍这些命令,因为它们有点超出了本书的范围。有关更多信息,请参阅每个命令的手册页。

总结

在本章中,我们看到了类Unix系统(如Linux)如何管理用户权限,以允许对文件和目录进行读取、写入和执行访问。这个权限系统的基本思想可以追溯到Unix的早期,并且经受住了时间的考验。但是类Unix系统中的本机权限机制缺乏更现代系统的精细粒度。