电脑技术学习

对话 UNIX,第 4 部分: UNIX 所有权和权限管理

dn001

  从大约 50 年前电子时代的开始直到 1977 年出现了 Apple 计算机,完成计算工作的硬件设备一直很缺乏,并且购买和运行它们也非常的昂贵。当时,这些(相对)原始的系统非常珍贵,仅仅用来处理那些最复杂的问题。不同的项目之间必须竞争才能获得机时,而最早的信息技术 (IT) 管理人员的任务是保持系统每天 24 小时、每个星期 7 天不间断地进行工作。毕竟,每一秒的闲置都等于浪费金钱。

  在理想的情况下,可以根据需要将这些浪费掉的 时间自动地分配给任何处于就绪状态等待进行计算的任务。实际上,这正是分时 (time-sharing) 的基本思想(由 Robert Berner 在 1957 年提出)。在 Multics、RSTS/E 和后来的 Unix® 及其最新的变种中,都实现了分时或多任务,对计算机资源(CPU、输入和输出、以及内存)进行划分,分配给多个等待执行的作业,使得看起来每个作业都独占了计算机。可以在多任务大型机中附加一些虚拟终端,这样每个终端都可以看作一台个人计算机。

  现在,您很可能拥有自己的 UNIX 计算机,或者与其他用户共享功能更强大的多处理器系统。但无论是您的便携式计算机、或者公共机房中的 UNIX 庞然大物,都可能需要进行同时访问。UNIX 提供了健壮的工具和基础结构,以便帮助您保护和共享信息。

  本文介绍了用户权限,特别是研究了如何对文件权限进行操作,以便对其他用户限制或共享您的目录和文件。如果您希望流畅地与 UNIX 进行对话,那么了解相关的权限是至关重要的。

  ID 和 UID

  在开始之前,让我们来看看您使用的究竟是哪个用户。在命令提示符处,输入 whoami:

$ whoami
strike

  我的计算机回答 strike,这是我的用户名(即登录时所使用的名称)。您的 whoami 应该返回您的登录名称。

  当然,您的用户名是用户 ID (UID) 的假名(pseudonym)。要查看您的 UID,可以输入 id -u:

$ id -u
501

  在本示例中,我的 UID 为 501。

  通常,尽可能地使用用户名而不是 UID,因为用户名易于阅读和记忆。例如,如果您运行 ps uxf 命令以查看您的运行进程的列表,那么 ps 将显示您的用户名作为您的进程的所有者。

$ ps uxf
USER    PID %CPU %MEM  VSZ RSS TTY   STAT START  TIME COMMAND
strike  32346 0.0 0.1 6496 1832 ?    S  19:39  0:00 sshd: strike@pts/0
strike  32347 0.0 0.1 2592 1476 pts/0  Ss  19:39  0:00 _ -bash
strike  32358 0.0 0.0 2476 820 pts/0  R+  19:39  0:00   _ ps uxf

  输出结果中显示了 3 个进程,分别是:一个 ssh 登录进程,它产生了一个 bash Shell,而后者启动了 ps 命令。类似地,如果您在自己的 home 目录中运行 ls -alFG 以查看您的文件的所有者,那么将显示您的用户名而不是您的 UID。

  通常,只有您可以中断自己的任务。(当然,超级用户 root 可以控制和操作所有的任务。)例如,joe(共享相同系统的另一个用户)不能终止我正在运行的 Shell,即上面列表中的进程 32347:

$ whoami
joe
$ kill -INT 32347
-bash: kill: (32347) - Operation not permitted

  其中,32347 是我的 Shell 的进程 ID,joe 可以通过运行 ps auxf 找到该信息。然而,因为该进程由我所拥有,所以 joe 不能终止它。与此相反,我当然可以结束自己的任何任务,如清单 1 所示。

  清单 1. 结束自己的进程

$ ps uxf
...
strike  32347 0.0 0.1 2592 1488 pts/0  Ss  19:39  0:00 _ -bash
strike  32733 39.5 0.0 1480 356 pts/0  R  19:50  0:01   _ yes
$ kill -INT 32733
$ ps uxf
...
strike  32347 0.0 0.1 2592 1488 pts/0  Ss  19:39  0:00 _ -bash

  在运行了 kill -INT 32733 之后,终止了进程 32733(yes 命令)。

  尽管这是个比较简单的概念,但严格的所有权和针对每个用户的预置,这两种特性使得 UNIX 远比 Microsoft® Windows® 更加安全。

  成员具有相应的权限

  与您所启动的作业一样,您还拥有您所创建的目录和文件。例如,在您的 home 目录中运行 ls -alFG 命令和 $HOME 以查看您所拥有的内容,如清单 2 所示。

  清单 2. 列出您在自己的 home 目录中所拥有的内容

$ ls -alFG $HOME
...
-rw-------  1 strike   6175 Aug 25 07:03 .bash_history
-rw-------  1 strike   567 Apr 20 2005 .bash_profile
-rw-------  1 strike   1834 Apr 20 2005 .bashrc
drwx------  2 strike   4096 Mar 8 10:54 .ssh/
-rw-------  1 strike   9516 Aug 22 16:42 .viminfo
-rw-r--r--  1 strike 1529617 Jul 19 07:00 Archive.zip
drwxrwx---  3 strike   4096 Aug 24 04:04 IBM/
drwxr-xrwx  3 strike   4096 Jun 14 06:06 backups/
...

  UNIX 组中存在的问题

  要在组中的所有成员之间共享文件,可以更改文件的组所有者,这是一种非常简单的方法。例如,如果由您、jane 和 joe 组成了 scIEnce UNIX 组,并且您希望与这两个用户共享敏感的 nuclear.csv 数据文件,只需要将该文件的组所有者更改为 science 即可。

  但是,如果 sam 和 bertha 也需要访问该文件,而他们都不属于 science 组,那又应该怎么办呢?当然,您可以将这两个用户加到 science 中,但这样做将允许他们访问 science 组所拥有的所有 文件。

  这是 UNIX 组实现中的一个局限性:一个文件有且只能有一个组所有者,而要实现复杂的共享方案通常会导致组的数目激增。(您可以为 joe、jane、sam 和 bertha 创建一个新的组,比如 jjsb。但是当 donald 也需要访问时,又应该怎么办呢?)

  如果您需要使用复杂的访问控制方案,可以考虑使用访问控制列表 (ACL),许多 UNIX 实现都提供了这种机制。ACL 对标准的 UNIX 所有权模型进行了扩展,可以对每个用户或每个组授予(或撤销)特定的权限。ACL 就像是在门口设置了一个保镖:可以让您的伙伴、某些名流和经过筛选的客人进入,而将无业游民和其他乌合之众拒之门外。

  正如您看到的,我拥有我的 home 目录中的所有目录和文件。作为所有者,我可以删除、重命名和移动我的任何文件和目录,并且可以编辑我的任何文件。您对自己的文件(除非特别指明,这里的文件 同时表示文件和目录)具有相同的权限。

  另外,您可以决定与其他的用户共享 您的文件。实际上,因为 UNIX 是一种多用户系统,所以共享文件是该操作系统的基本理念之一。

  除了特定的用户所有者,每个文件和目录还具有一个组 所有者。UNIX 组 只是一些用户的集合,而您可以作为一个或多个组中的成员。使用 id 可以查看您的成员信息:

$ id
uid=501(strike) gid=501(strike) groups=501(strike),
 81(appserveradm), 79(appserverusr), 80(admin)

  在我的系统中,我的主要组的组 id (GID) 为 501,该组名为 strike。我还属于其他的 3 个组:

  appserveradm

  appserveruser

  admin

  在通常情况以及缺省情况下,您所创建的文件的组所有者为您的主要组,但是您可以将组所有者更改为您所属的任何组。在您的 home 目录中运行 ls -laF,可以显示有关您的文件的更多信息,如清单 3 所示。

  清单 3. 显示有关您的文件的更多信息

-rw-------  1 strike strike   6118 Aug 27 21:59 .bash_history
-rw-r--r--  1 strike strike   567 Apr 20 2005 .bash_profile
-rw-r--r--  1 strike strike   1834 Apr 20 2005 .bashrc
drwx------  2 strike strike   4096 Mar 8 10:54 .ssh/
-rw-------  1 strike strike   9516 Aug 22 16:42 .viminfo
-rw-r--r--  1 strike strike 1529617 Jul 19 07:00 Archive.zip
drwxr-xr-x  3 strike strike   4096 Aug 24 04:04 IBM/
drwxrwxr-x  3 strike admin   4096 Jun 14 06:06 backups/

  注意: 清单 3 显示了 ls -l 的典型输出。清单 2 看起来有些不同,这是因为在前面的讨论中出于简化的目的,有意隐藏了组所有者的信息。您可以使用 -G 隐藏组所有者。

  名为 backups 的目录的组所有者为 admin,它将某些权限给予了组中所有的成员。同时,我的其他文件的组所有者为 strike。通常,一个用户是他或她的同名组中的唯一成员,这个同名组有效地将访问权限限制于该用户。

  细节内容

  如果您回头再看看上面的 ls 的输出结果,您将注意到,每行内容的开头有一个由 10 个字符组成的序列。每个字符都是一个开/关设置或位,后者表示了三类用户(您本人、您的一个组和其他用户)的某一种特定的权限。图 1 显示了每一位的用法。

  图 1. UNIX 文件的权限位

  在图 1 中:

  起始位表示该文件是否为目录(通常,起始位 表示该文件是否为特殊文件。如果该文件是特殊文件,起始字符 d 表示目录、l 表示符号链接,等等)。这个设置是无法改变的。

  接下来的三位(用蓝色表示的)分别表示您 对该文件的读、写和执行权限。您可以禁用写权限位,例如要防止删除文件。(是的,要删除一个文件,您需要写权限。)

  接下来的三位(用绿色表示的)表示组 对该文件的读、写和执行权限。

  最后的三位(用橙色表示的)表示所有其他 用户(即除了您自己以及您的组中的成员之外的所有用户)的权限。

  可以使用 ls -laF 的输出作为示例查找上述内容:

  只有我可以读和写 .bash_history、.bash_profile、.bashrc 和 .viminfo 文件。我可以查看、编辑和删除这些文件。

  只有我可以访问 .ssh 目录。第一位表示它是一个特殊的文件,d 表示目录。我可以显示该目录中的内容,因为已经设置了它的用户读位。我可以在该目录中添加和删除文件,因为已经设置了它的用户写位。您可能奇怪为什么该目录是用户可执行的。除非设置了该位,否则无法遍历目录(进入目录并列举目录)。(另外,正如本系列的第 3 部分中所提到的,您的 .ssh 目录必须是您私有的,否则您的公钥访问无法正常工作。)

  我可以读和写 Archive.zip 文件,并且其他用户可以读该文件。(当然,strike 组也可以读该文件,但如果我是该组中唯一的成员,那么这个权限是没有实际意义的。)

  我可以列举、读和写 IBM(另一个目录)中的文件,而其他用户可以列举其中的内容。

  最后,admin 组的成员和我可以列举、读和写 backups 目录中的文件,而其他用户可以列举和读。

  设置目录的保护 (sticky) 位

  如果您希望确保一个目录持久,而不会被意外地删除,那么可以使用 chmod +T 设置其保护 位。

$ ls -lF
drwxrwxrwx  2 strike strike  68 Aug 28 06:21 dropbox/
drwx------  2 strike strike  68 Aug 28 06:21 mine/
$ chmod +t dropbox
$ ls -lF
drwxrwxrwt  2 strike strike  68 Aug 28 06:21 dropbox/
drwx------  2 strike strike  68 Aug 28 06:21 mine/

  设置保护位并将权限设置为所有用户都可以读、写和执行,每个用户都可以在 dropbox 目录中放置文件,但只有我能够删除该目录中的文件或该目录本身。

  如果您运行 ls -ld /tmp,这个用作应用程序临时空间的系统范围临时目录可能是保护的。

  您可以使用 chmod(更改模式 change mode)命令修改相应的权限(除了目录位之外)。您可以使用 chgrp(更改组 change group)命令来修改文件所属的组。(超级用户 root 也可以使用 chown 或 change owner 命令来更改文件所有权。)

  下面是 chmod 的示例应用程序:

  chmod u+x script.sh:如果您编写了一个 Shell 脚本,并且希望执行它,那么需要设置其执行位。其中,短语 u+x 表示对用户所有者 (u) 设置 (+) 执行位 (x)。chmod 的一般形式是 chmod,不指定用户(即表示用户)、一个或多个 u、g(表示组)、或 o(表示其他用户),+ 或 -,以及一个或多个 r、w 和 x。

  chmod go+rx IBM:这个命令为组和其他用户设置了读和执行权限。

  chmod a+rx script.sh:除了 u、g 和 o 以外,您还可以使用修饰符 a 来表示所有用户 或用户、组和其他用户。因此,这个命令为所有的三类用户设置了读和执行权限。

  chgrp admin backups:这个命令将 backups 目录的组所有者更改为 admin。

  如果使用 + 添加权限,它将会添加指定的权限,但不会修改其他的权限。与之类似,如果使用 -(减号)撤消权限,它将会禁用某些权限,但不会修改其他的权限。如果您希望一次设置所有的权限,可以使用数值文件模式。(您还可以使用 chmod = 操作符。有关详细的内容,请参见手册页面。)

  注意: 数值文件模式 是从 0 到 7 的 8 进制数字,或三位的数值,其中每一位分别表示读、写和执行。因为对于每个文件都有三类用户,所以完整地指定文件模式需要三个数字,如 400、644 或 777。下面提供了一些示例:

  要让一个目录成为私有的,可以为自己设置权限,而撤销组和其他用户的权限:

$ mkdir example
$ ls -l
drwxr-xr-x  2 strike strike    68 Aug 28 11:27 example
$ chmod 700 example
$ ls -l
drwx------  2 strike strike    68 Aug 28 11:27 example

  模式 700 可以表示为用户设置读、写和执行权限(开头的 7),而禁用所有其他的权限(后面的两个 0)。

  如果您希望让该计算机上其他的用户可以读取您的文件,可以为所有的三类用户设置读权限:

$ ls -l .aliases
-rw-------  1 mstreich mstreich 79 Jul 26 17:08 .aliases
$ chmod 644 .alias
$ ls -l
-rw-r--r-- 1 mstreich mstreich 79 Jul 26 17:08 .aliases

  644 是一种缩写,它表示为我设置读和写权限 (6),并为组 (4) 和其他用户 (4) 设置读权限。当然,如果您的 home 目录中存在 .aliases 文件,那么必须将 $HOME 设置为允许列举和读。

  表 1 给出了用户所有者、组所有者和其他用户的数值及其关联的结果。只需在每个部分中加上相应的值,就可以找到合适的值进行设置。

  表 1. 数值及其关联的结果

某类用户结果
用户0400允许所有者读。
0200允许所有者写。
0100对于文件,允许所有者执行,对于目录,允许所有者在该目录中进行搜索。
0040允许组成员读。
0020允许组成员写。
0010对于文件,允许组成员执行,对于目录,允许组成员在该目录中进行搜索。
其他用户0004允许其他用户读。
0002允许其他用户写。
0001对于文件,允许其他用户执行,对于目录,允许其他用户在该目录中进行搜索。

  例如,要为其他用户设置读和写权限,可以将 0004 加上 0002 以产生 0006。对于用户和组,可以进行类似的操作,可以将三个总数加在一起,以产生完全限定的数值模式。

  权限是非常重要的

  在 UNIX 系统中,需要不断地设置和管理相关权限。通常,您需要对特定文件和目录具有适当的权限,以便运行一些守护进程;只有设置了正确的权限,这些目录(如 /tmp)才能正常工作;当然,要与其他用户共享某些文件,或保护您的文件不让其他用户访问,必须能够设置、更改和读取相应的权限。

  本系列中的下一篇文章将继续介绍文件,并研究在多台计算机上对大量的文件进行管理的实用程序和技术。

标签: