为了最有效地利用本系列中的文章,您应该具有基本的 Linux 知识,并需要准备一个 Linux 系统,用于练习本文介绍的命令。有时候不同版本的程序输出格式不同,因此您所得到的结果未必总是与这里所示的清单和图相同。
用户和组
现在,您了解了 Linux 是一个多用户的系统,每个用户属于一个主要 组,也可能是附加组。也可以作为一个用户登录,然后使用 su
或者 sudo -s
命令变为另一个用户。Linux 的文件所有权和访问授权是与用户 id 和组密切相关的,所以我们要复习一下基本的用户和组信息。
我是谁?
如果没有切换到其他用户,您的 id 就是登录时的。如果切换到其他用户,在本文的大多数例子中,您的提示中就会包括您的用户 id。如果您的提示没有包括用户 id,可以使用 whoami
命令来检查您当前有效的 id。清单 1 显示了一些例子,说明了提示字符串(来自 PS1 环境变量)与本文中的其他例子不同。在提示字符串中包含您的 id 是一个有用的功能。
清单 1. 决定有效的用户 id
/home/ian$ whoami tom /home/ian$ exit exit $ whoami ian |
我在什么组中?
类似的,您可以使用 groups
命令找出您在什么组中。使用 id
命令,您可以找出用户和组信息。添加一个用户 id 参数到 groups
或者 id
来查看该用户 id 的信息,而并非当前用户 id。查看 清单 2 中的示例。请注意,没有用户 id,id
命令也会显示 SELinux 上下文和基本 id 信息。
清单 2. 决策组成员
[ian@echidna ~]$ id uid=1000(ian) gid=1000(ian) groups=1000(ian),505(development),8093(editor) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [ian@echidna ~]$ id ian uid=1000(ian) gid=1000(ian) groups=1000(ian),8093(editor),505(development) [ian@echidna ~]$ groups ian development editor [ian@echidna ~]$ id tom uid=1012(tom) gid=1012(tom) groups=1012(tom),505(development) [ian@echidna ~]$ groups tom tom : tom development [ian@echidna ~]$ su tom Password: [tom@echidna ian]$ groups tom development [tom@echidna ian]$ groups ian ian : ian editor development |
文件的所有权和权限
如果每个用户都有 id 并且是主要组的成员,那么 Linux 系统上的每个文件都有一个所有者和与其相关的组。
普通文件
使用 ls -l
命令显示所有者和组。
清单 3. 决定文件所有权
[ian@echidna ~]$ ls -l /bin/bash .bashrc helloworld.C -rw-r--r--. 1 ian ian 124 Mar 31 2010 .bashrc -rwxr-xr-x. 1 root root 943360 May 21 2010 /bin/bash -rw-rw-r--. 1 ian development 116 Nov 30 10:21 helloworld.C |
在这个特殊的例子中,用户 ian 的 .bashrc 文件由他自己所有,并且属于 ian 的主要组。类似的,/bin/bash 由用户 root 所有,并且位于组 root。但是,helloworld.C 由用户 ian 所有,但是属于组 development。用户名和组名来自不同的名称空间,所以给定的名称可能同时是用户名和组名。事实上,很多版本默认为每个新用户创建一个匹配的组。
Linux 权限模型每个文件系统对象有 3 种类型。这些权限就是读(r),写(w)和执行(x)。写权限包括修改和删除对象的能力。此外,这些权限被分别指定给文件所有者、文件组成员和其他人。
回到清单 3 第一列,注意,它包括一个 11 个字符的字符串。这第 11 个字符是最近才添加的。我们稍后再讨论。第一个字母描述了对象的类型(-
在这个例子中表示普通文件),剩下的 9 个字母每三个字母为一组。第一组表示文件所有者的读、写和执行权限。-
表示相应的权限没有被授予。因此,用户 ian 就可以读和写 .bashrc 文件,但是不能执行它;而 root 可以读、写 和 执行 /bin/bash 文件。第二组表示文件组的读、写和执行权限。development 组的成员能够读或者写 ian 的 helloworld.C 文件,而其他人只能读。类似的,root 组中的成员和其他人能够读或者执行 /bin/bash 文件。
目录
目录和常规文件一样使用相同的权限标识,但是它们的翻译不同。目录的读权限允许用户使用该权限列出目录内容。写权限意味着用户使用该权限能够在目录中创建或者删除文件。执行权限允许用户输入目录并访问任意子目录。没有执行权限,目录下的文件系统对象就是不可访问的。没有读权限,目录下的文件系统对象在目录清单下就是不可见的,但是如果知道磁盘上对象的完整路径,这些对象仍是可访问的。清单 4 是说明这些问题的非常人工的例子。
清单 4. 权限和目录
[ian@echidna ~]$ ls -l /home total 32 drwxr-x---. 38 editor editor 12288 Nov 30 10:49 editor drwxr-x---. 4 greg development 4096 Nov 30 12:44 greg drwx------. 21 gretchen gretchen 4096 Nov 30 11:26 gretchen drwxr-xr-x. 41 ian ian 4096 Nov 30 10:51 ian drwx------. 21 ianadmin ianadmin 4096 May 28 2010 ianadmin d-wx--x--x. 21 tom tom 4096 Nov 30 11:30 tom [ian@echidna ~]$ ls -a ~greg/.ba* /home/greg/.bash_history /home/greg/.bash_profile /home/greg/.bash_logout /home/greg/.bashrc [ian@echidna ~]$ ls -a ~gretchen ls: cannot open directory /home/gretchen: Permission denied [ian@echidna ~]$ ls -a ~tom ls: cannot open directory /home/tom: Permission denied [ian@echidna ~]$ head -n 3 ~tom/.bashrc # .bashrc # Source global definitions |
长清单的第一个字母表示对象的类型(d
表示目录)。用户 greg 的主目录有 development 组成员的读和写权限,因此用户 tom 和 ian 能够列出目录。用户 gretchen 的主目录没有 gretchen 组或者其他用户的读和执行权限,所以用户 ian 不能访问它。用户 tom 的主目录有执行权限,但是没有读权限,所以用户 ian 不能列出内容,但是如果知道对象存在,就可以访问目录下的对象。
其他文件系统对象
ls -l
的输出可能包含文件系统对象,而不是文件和目录,如清单中第一个字母所示。在后面的文章中我们还会见到更多,但是现在,只是说明可能的对象类型。
表 1. 文件系统对象类型
代码 | 对象类型 |
---|---|
- | 常规文件 |
d | 目录 |
l | 符号链接 |
c | 字符特殊设备 |
b | 模块特殊设备 |
p | FIFO |
s | 套接字 |
第 11 个字符
来自 ls
命令中长清单的第 11 个字符是最近才出现的,所以部分版本仍只显示头 10 个字符。在其他情况下,第 11 个字符是一个空格,所以您可能没有注意到。这个字符表示是否有替换的访问方法应用到文件。当跟随文件模式位的字符是空格时,就表示没有替换访问方法。当是一个可打印字符时,就有替换方法。这个方法可能是例子的访问控制清单。GNU ls
使用一个 ‘.’(点)来表示文件只有一个 SELinux 安全上下文。有其他替换访问方法的文件用 ‘+’(加号)表示。
变更权限
添加权限
假设您创建一个 “Hello world” 的 shell 脚本。当您第一次创建脚本时,它通常是不可执行的。使用 chmod
命令和 +x
选项添加执行权限,如清单 5 所示。
清单 5. 创建可执行的 shell 脚本
[ian@echidna ~]$ echo 'echo "Hello world!"'>hello.sh [ian@echidna ~]$ ls -l hello.sh -rw-rw-r--. 1 ian ian 20 Nov 30 13:05 hello.sh [ian@echidna ~]$ ./hello.sh bash: ./hello.sh: Permission denied [ian@echidna ~]$ chmod +x hello.sh [ian@echidna ~]$ ./hello.sh Hello world! [ian@echidna ~]$ ls -l hello.sh -rwxrwxr-x. 1 ian ian 20 Nov 30 13:05 hello.sh |
您可以按类似的方法使用 +r
来设置读权限,使用 +w
设置写权限。事实上,您可以联合使用 r
、w
和 x
。例如,使用 chmod +rwx
将会设置文件的所有读、写和执行权限。chmod
会添加尚未设置的权限。
可选性
您在上面的例子中可能已经注意到,执行权限被设置给所有者、组 和 其他。为了更具可选性,您可以给模式描述加前缀 u
来设置用户权限,g
来设置组权限,还有 o
为其他人设置。需要指出的是 a
设置所有用户的权限,这就相当于忽略它。清单 6 显示了如何添加用户和组写和执行权限到 shell 脚本的其他副本。
清单 6. 有选择性地添加权限
[ian@echidna ~]$ echo 'echo "Hello world!"'>hello2.sh [ian@echidna ~]$ chmod ug+xw hello2.sh [ian@echidna ~]$ ls -l hello2.sh -rwxrwxr--. 1 ian ian 20 Nov 30 13:08 hello2.sh |
删除权限
有时您需要删除权限,而不单单是添加。简单地将 +
改变为 -
,就能删除任何已设置的指定权限。清单 7 显示了如何删除两个 shell 脚本上的其他用户的所有权限。
清单 7. 删除权限
[ian@echidna ~]$ ls -l hello*.sh -rwxrwxr--. 1 ian ian 20 Nov 30 13:08 hello2.sh -rwxrwxr-x. 1 ian ian 20 Nov 30 13:05 hello.sh [ian@echidna ~]$ chmod o-xrw hello*.sh [ian@echidna ~]$ ls -l hello*.sh -rwxrwx---. 1 ian ian 20 Nov 30 13:08 hello2.sh -rwxrwx---. 1 ian ian 20 Nov 30 13:05 hello.sh |
请注意,您可以一次改变一个或者多个文件的权限。正如在 topic 103 的文章中看到其他命令一样,您甚至可以使用 -R
(或者 --recursive
)选项在目录和文件上进行递归操作。
设置权限
现在已经可以添加或者删除权限了,您可能会想,怎样才能只设置一些特殊权限。使用 =
替换 +
或者 -
来完成这个动作。要在上述脚本中设置权限,这样其他用户就没有访问权利,您可以使用 chmod o= hello*
替换我们用于删除权限的命令。
如果您想对用户、组合或其他设置不同的权限,您可以通过逗号分隔不同的表达;例如,ug=rwx,o=rx
,或者您可以使用稍后提到的数字权限。
八进制权限
目前为止,您都是使用符号(ugoa 和 rxw)来指定权限。每组中有三个可能的权限。您还可以使用八进制取代符号设置权限。按这种方法设置的权限使用高达 4 位八进制数字。讨论属性时,我们会查看第 1 个数字。第 2 个数字定义了用户权限,第 3 个是组权限,第 4 个是其他权限。这三个数字中的每一个都通过添加所需的权限设置来构建:读(4),写(2)和执行(1)。在 清单 5 中的 hello.sh 例子中,创建的脚本有权限 -rw-r--r--,相当于八进制 644。设置每个人的执行权限将模式改为 755。
当您想要一次设置所有权限,而不给予每个组相同权限时,设置使用数字权限非常方便。使用 表 2 作为一个方便的八进制权限参考。
表 2. 数字权限
符号 | 八进制 |
---|---|
rwx |
7 |
rw- |
6 |
r-x |
5 |
r-- |
4 |
-wx |
3 |
-w- |
2 |
--x |
1 |
--- |
0 |
suid 和 sgid
Linux 权限模型有两个特殊的访问模式,名为 suid(设置用户 id)和 sgid(设置组 id)。当可执行的程序设置为 suid 访问模式,它就会开始运行,好像是由文件所有者启动而不是由真正启动它的用户启动。类似的,设置为 sgid 访问模式,程序就会运行,好像启动用户属于文件组,而不属于他所有的组。可以单独或者同时设置两个访问模式。
清单 8 显示了可执行的 passwd
由 root 所有:
清单 8. /usr/bin/passwd 上的 suid 访问模式
[ian@echidna ~]$ ls -l /usr/bin/passwd -rwsr-xr-x. 1 root root 34368 Apr 6 2010 /usr/bin/passwd |
请注意,在用户的权限三件套中 x
的位置上有一个 s
。这就表示,对这个特定的程序来说,suid 和可执行位已经被设置。所以,当 passwd
运行时,它就会像 root 用户使用完全的 superuser 访问一样加载它运行,而不是作为想运行该程序的用户。因为 passwd
和 root
访问一起运行,所以它可以修改 /etc/passwd。
suid 和 sgid 位与长目录清单中用户和组的 x
占据相同的空间。如果文件是可执行的,suid 或 sgid 位如果已设置,将会显示为小写的 s
,否则就显示为大写的 S
。
虽然 suid 和 sgid 很便利,甚至在很多环境下是必需的,但是这些访问模式不适当的使用会造成系统安全上的漏洞。您要尽量少地使用 suid 程序。passwd
命令是少数 必须 为 suid 的命令之一。
设置 suid 和 sgid
suid 和 sgid 位使用字母 s
在符号上进行设置和重设;例如,u+s
设置 suid 访问模式,g-s
删除 sgid 模式。在八进制格式中,suid 在第一位(高阶)为值 4,而 sgid 是值 2。
目录和 sgid
当一个目录使用 sgid 模式时,在这个目录中创建的任何文件和目录将会继承目录的组 id。这个对那些被从事同一项目的一组人使用的目录树极为有用。 清单 9 显示了用户 greg 任何设置一个 development 组所有用户都能使用的目录,以及一个示例,用户 gretchen 如何在目录上创建一个文件。正如所创建的,文件 gretchen.txt 允许组成员编辑文件,因此 gretchen 使用 chmod g-w
来取消组的写功能。
清单 9. sgid 访问模式和目录
[greg@echidna ~]$ mkdir lpi101 [greg@echidna ~]$ chmod g+ws lpi101 [greg@echidna ~]$ ls -ld lpi101 drwxrwsr-x. 2 greg development 4096 Nov 30 13:30 lpi101/ [greg@echidna ~]$ su - gretchen Password: [gretchen@echidna ~]$ touch ~greg/lpi101/gretchen.txt [gretchen@echidna ~]$ ls -l ~greg/lpi101/gretchen.txt -rw-rw-r--. 1 gretchen development 0 Nov 30 14:12 /home/greg/lpi101/gretchen.txt [gretchen@echidna ~]$ chmod g-w ~greg/lpi101/gretchen.txt [gretchen@echidna ~]$ ls -l ~greg/lpi101/gretchen.txt -rw-r--r--. 1 gretchen development 0 Nov 30 14:12 /home/greg/lpi101/gretchen.txt |
development 组的任何成员现在都能够在用户 greg 的 lpi101 目录上创建文件了。正如 清单 10 所示,组的其他用户不能升级文件 gretchen.txt。但是,他们有对目录的写权限,因此可以删除文件。
清单 10. sgid 访问模式和文件所有权
[gretchen@echidna ~]$ su - tom Password: [tom@echidna ~]$ echo "something" >> ~greg/lpi101/gretchen.txt -bash: /home/greg/lpi101/gretchen.txt: Permission denied [tom@echidna ~]$ rm ~greg/lpi101/gretchen.txt rm: remove write-protected regular empty file `/home/greg/lpi101/gretchen.txt'? y [tom@echidna ~]$ ls -l ~greg/lpi101/ total 0 |
粘贴位
您刚看到了任何有目录写权限的人如何删除目录中的文件。这对一个工作组项目是可接受的,但是对全球共享的文件空间,例如 /tmp 目录,是不希望的。幸运的是,有解决方案。
剩下的访问模式为就称为粘贴 位。用符号表示就是 t
,用数字表示就是八进制位的高阶为 1。它显示在其他用户的可执行标识中(最后的字符)的长目录清单,而且 suid 和 sgid 的大小写意义相同。如果设置一个目录,它只允许有所有权的用户或者 superuser(root)删除或者解除文件链接。清单 11 显示了用户 greg 如何在他的 lpi101 目录上设置粘贴位,还显示了这个位设置用于 /tmp。
清单 11. 粘贴目录
[greg@echidna ~]$ chmod +t lpi101 [greg@echidna ~]$ ls -ld lpi101 /tmp drwxrwsr-t. 2 greg development 4096 Nov 30 14:16 lpi101 drwxrwxrwt. 24 root root 12288 Nov 30 14:22 /tmp |
在以前,UNIX® 系统曾在文件上使用粘贴位在交换空间囤积可执行文件,避免重新加载。现代 Linux 内核忽略了粘贴位,如果它是设置给文件的。
访问模式的总结
表 3 总结了这里讨论的 3 种访问模式的符号和八进制表示。
表 3. 访问模式
访问模式 | 符号 | 八进制 |
---|---|---|
suid | s with u |
4000 |
sgid | s with g |
2000 |
sticky | t |
1000 |
将这些和早先的权限信息结合在一起,您可以看到对应 greg 的 lpi101 权限和 drwxrwsr-t 访问模式的完整的八进制表示是 3775。虽然 ls
命令不显示八进制权限,您可以使用 find
命令进行显示,如清单 12清单 12 所示。
清单 12. 可打印的符号和八进制权限
[greg@echidna ~]$ find . -name lpi101 -printf "%M %m %f\n" drwxrwsr-t 3775 lpi101 |
不可变文件
访问模式和权限提供了广泛的控制,限制了谁可以在文件和目录上做什么。但是,它们对有些事情也不能避免,如 root 用户对文件的无心删除。虽然这不在 LPI Topic 104.5 的范围内,但是在提供额外功能的文件系统上还是有些可用的附加属性。其中之一就是不可变 属性。设置完成后,即使是 root 用户也不能删除文件,直到属性解除。
使用 lsattr
命令查看文件或者目录是否设置了不可变标识(或者任何其他属性)。要将一个文件设置为不可变,使用 chattr
命令和 -i
标识。
清单 13清单 13 显示了用户 root 可以创建一个不可变文件,但是不能删除它,直到不可变标识被删除。
清单 13. 不可变文件
[root@echidna ~]# touch keep.me [root@echidna ~]# chattr +i keep.me [root@echidna ~]# lsattr keep.me ----i--------e- keep.me [root@echidna ~]# rm -f keep.me rm: cannot remove `keep.me': Operation not permitted [root@echidna ~]# chattr -i keep.me [root@echidna ~]# rm -f keep.me |
变更不可变标识需要 root 授权,或者最少 CAP_LINUX_IMMUTABLE 功能。使文件不可变通常是安全或者入侵检测工作的一部分。见功能使用页面(man capabilities
)了解更多信息。
文件创建屏蔽
创建一个新文件时,创建进程就会指明新文件的权限。通常,所需的模式是 0666,它使文件可由任何人读和写。目录默认为 0777。但是,这个宽松的创建会受到 umask 值的影响,这个值指明了用户不想自动授予新创建的文件或者目录什么权限。系统使用 umask 值来减少原始请求的权限。您可以使用 umask
查看 umask 设置,如清单 14清单 14 所示。
清单 14. 显示八进制 umask
[ian@echidna ~]$ umask 0002 |
请记得,umask 指定了那个权限不被授予。在 Linux 系统上,用户没有专用组的的情况下,umask 通常默认为 0022,它可以从新文件中删除组和其他写权限。用户有专用组的情况下(例如这些例子中使用的在 Fedora 系统上),umask 通常默认为 0002,它删除了其他用户的写权限。使用 -S
选项来从符号上显示 umask,以显示哪个权限被允许的形式。
使用 umask
命令设置一个 unmask 并显示。所以,如果您想要保持文件更专有,并且不允许所有组或者其他人访问新创建的文件,就是可以使用 umask 值 0077。或者从符号上,使用 umask u=rwx,g=,o=
进行设置,如清单 15清单 14 所示。
清单 15. 设置 umask
[ian@echidna ~]$ umask -S u=rwx,g=rwx,o=rx [ian@echidna ~]$ umask u=rwx,g=,o= [ian@echidna ~]$ umask 0077 [ian@echidna ~]$ touch newfile [ian@echidna ~]$ ls -l newfile -rw-------. 1 ian ian 0 Nov 30 15:40 newfile |
设置文件所有者和组
文件组
要变更文件的组,使用 chgrp
命令和组名,以及一个或者多个文件名。如果您喜欢,还可以使用组编号。普通用户必须拥有文件,同时是文件要变更到的组的组员。root 用户可以将文件变更到任意组。清单 16清单 16 显示了一个例子。
清单 16. 变更组的所有权
[ian@echidna ~]$ touch file{1,2} [ian@echidna ~]$ ls -l file* -rw-rw-r--. 1 ian ian 0 Nov 30 15:54 file1 -rw-rw-r--. 1 ian ian 0 Nov 30 15:54 file2 [ian@echidna ~]$ chgrp development file1 [ian@echidna ~]$ chgrp 505 file2 [ian@echidna ~]$ ls -l file* -rw-rw-r--. 1 ian development 0 Nov 30 15:54 file1 -rw-rw-r--. 1 ian development 0 Nov 30 15:54 file2 |
正如该教程中的许多其他命令,chgrp
有一个 -R
选项,允许将变更递归应用到所有所选的的文件和子目录中。
默认组
当您学习之前的 访问模式 时,您就了解了在目录上设置 sgid 模式如何导致创建在该目录下的新文件属于目录的组,而不是属于创建该文件的用户所在的组。
您还可以使用 newgrp
命令来暂时地将您的初级组变更到您所在的其他组。创建一个新的 shell,当您退出 shell 时,之前的组就能恢复,如清单 17清单 17 所示。
清单 17. 使用 newgrp 来暂时改变默认组
[ian@echidna ~]$ groups ian development editor [ian@echidna ~]$ newgrp development [ian@echidna ~]$ groups development ian editor [ian@echidna ~]$ touch file3 [ian@echidna ~]$ ls -l file3 -rw-r--r--. 1 ian development 0 Nov 30 16:00 file3 [ian@echidna ~]$ exit [ian@echidna ~]$ groups ian development editor |
文件所有者
root 用户可以使用 chown
命令变更文件的所有权。在它最简单的形式中,语法和 chgrp
命令类似,除了使用用户名或者数字 id,而不是组名或者 id。文件的组也可能通过在用户名或者 id 之后添加一个冒号和组名或者 id 来同时变更。如果只有给出冒号,那么就使用用户的默认组。一般来说,-R
选项会递归地应用变更。清单 18清单 18 给出了一个例子。
清单 18. 使用 chown 变更文件所有权
[ian@echidna ~]$ touch file4 [ian@echidna ~]$ su - Password: [root@echidna ~]# ls -l ~ian/file4 -rw-rw-r--. 1 ian ian 0 Nov 30 16:04 /home/ian/file4 [root@echidna ~]# chown greg ~ian/file4 [root@echidna ~]# ls -l ~ian/file4 -rw-rw-r--. 1 greg ian 0 Nov 30 16:04 /home/ian/file4 [root@echidna ~]# chown tom:gretchen ~ian/file4 [root@echidna ~]# ls -l ~ian/file4 -rw-rw-r--. 1 tom gretchen 0 Nov 30 16:04 /home/ian/file4 [root@echidna ~]# chown :tom ~ian/file4 [root@echidna ~]# ls -l ~ian/file4 -rw-rw-r--. 1 tom tom 0 Nov 30 16:04 /home/ian/file4 |
指定用户和组的较早版本使用点,而不是冒号。因为当名称中包含点时,这个可能会造成误解,所以已经不再推荐。
Linux 上的文件和目录权限介绍就到此为止。