内容纲要

🗂 | 查看 Linux 专题可浏览更多内容


查看权限

之前有提到,一般来说主目录是普通用户唯一有写入权限的地方。但这是怎么判断的?

$ ls -l /home
drwxr-xr-x 3 conners conners 4096 Mar 30 15:30 conners

这些信息表示为:

  • 权限:drwxr-xr-x
  • 硬链接数量:3
  • 文件属主:conners
  • 文件属组:conners
  • 文件的字节数大小:4096
  • 最后修改日期及时间:Mar 30 15:30
  • 文件名:conners

在 Unix 的安全模型中,用户可以拥有文件和目录。如果文件或目录属于某个用户,该用户(属主)拥有访问权。

用户反过来可以属于一个由一个或多个用户组成的组,这些用户被其属主赋予对文件和目录的访问权。

除了为属组授权,属主还可以为在 Unix 术语里这叫作「世界(world)」的(即除了属主与属组外的)其他用户授权。

也就是对应着 drwxr-xr-x,在之前的文章有提到第一个字母表示文件类型,剩余的每三个字母分别表示属主、属组和世界(其他用户)的权限:

文件类型 属主(Owner) 属组(Group) 世界(World)
d rwx r-x r-x

读取、写入与执行

简单来说,rwx 分别代表着「读取 r(ead)」、「写入 w(rite)」与「执行 x(ecute)」,如果是 - 则表示已禁用该权限。

权限 文件 目录
r 允许打开和读取文件 允许列出目录文件(需同时含有执行权限)
w 允许将文件写入或截断,但不允许重命名或删除文件(由目录属性决定)。 允许在目录内创建、删除及重命名文件(需同时含有执行权限)
x 允许将文件视为程序并执行,用脚本语言编写的程序文件也必须设置为可读才能执行 允许进入该目录

综上所述,drwxr-xr-x 表示这是一个目录,属主拥有读取、写入及执行权限,而属组和世界(其他用户)均有读写和执行权限但没有写入权限。

💡 你可能对属组还不是很明白,举个例子有这么一个目录:
drwxr-x--- 3 a www 4096 Mar 30 15:30 wwwroot
属主是用户 a,属组是 www。这时用户 b 没有权限的,因为其他用户权限是 ---
但让用户 b 加入到名为 www 到用户组就可以拥有权限 r-x

💡思考

那么当一个文件的属主没有写入权限而属组有写入权限时,如:
-----w---- 2 user1 group1 4.0K Aug 23 08:45 README

注意 user1 用户属于 group1 用户组,这时可以写入吗?

这是一个权限冲突的问题,属主权限是 ---,属组权限是 -w-,当遇到这样的情况时以属主权限为准,即便该用户属于有写入权限的用户组。

chmod:修改文件权限

文件的属主或超级用户可以使用 chmod 「Change Mode」命令修改文件或目录的模式(权限)。

chmod 命令有八进制表示法和符号表示法两种模式表示方式。

八进制表示法

八进制 二进制 模式
0 000
1 001 –x
2 010 -w-
3 011 -wx
4 100 r–
5 101 r-x
6 110 rw-
7 111 rwx

举个例子:

mkdir Documents && ls -l
drwxr-xr-x 2 conners conners 4096 Apr  8 11:32 Documents

这里新建了一个名为 Documents 的目录,并且可以看到权限是 rwxr-xr-x

按照八进制表示法就是 755,也就是依照 3 个八进制数位表示属主、属组与其他用户的权限。

💡 7 = 4(r) + w(2) + x(1)

那么如果想要将其他用户的权限禁止掉,即修改为 rwxr-x--- 就可以使用八进制表示法:

# chmod <八进制表示法> <目标文件或目录>
$ chmod 750 Documents

符号表示法

符号 含义
u 属主(user 缩写)
g 属组(group 缩写)
o 其他用户(other 缩写)
a 所有(all 缩写,等同于 u、g、o 一起设置)
+ 添加权限
移除权限
= 只赋予指定权限并移除其他权限

举几个例子:

# 为指定文件或目录的属组添加写入权限
$ chmod g+w <目标文件>

# 移除属主、属组与其他用户的写入权限
# 可以进一步简写为 -w 省去 a
$ chmod a-w <目标文件>

# 可以同时添加多个权限,如为属组同时添加写入与执行权限
$ chmod g+wx <目标文件>

# 等号会移除其他权限
# 如下,为属组与其他用户设置为仅有读取与执行权限,如果原有写入权限会被禁用
$ chmod go=rw <目标文件>

# 一次性为属主、属组与其他用户设置不同权限时,可用英文逗号隔开
$ chmod u+x,go=rx

chmod 命令选项

可以使用 --reference 选项复制已有文件的权限:

$ chmod --reference=<被复制权限文件> <复制权限文件>
$ chmod --reference=a.sh b.sh

如上,文件 b.sh 就拥有了和 a.sh 一样的文件权限。

chmod 还可以使用 -R 选项以递归的方式更新目录内所有文件的权限。但注意目录下的内容及子目录未必都是相同的属性,比如有的是可执行文件有的是文本文件。

在使用 chmod -R 进行执行权限调整需要谨慎,它不会去管执行权限对目录和普通文件有不同的含义。前面说过对于目录 x 表示进入目录,对于普通文件 x 表示执行。

特殊权限

除了读取、写入、执行权限之外还有其他一些较少用到的特殊权限设置。

setuid 位

$ ls -l /usr/bin/passwd /etc/passwd /etc/shadow
-rw-r--r-- 1 root root    1443 Apr  7 22:39 /etc/passwd
-rw-r----- 1 root shadow   974 Apr  7 22:39 /etc/shadow
-rwsr-xr-x 1 root root   63960 Feb  7  2020 /usr/bin/passwd

在使用 passwd 命令(/usr/bin/passwd)修改密码时,会修改存储密码的配置文件 /etc/shadow(在之前的文章有提到,历史上密码存储于 /etc/passwd 中但现在已经不是了)。

但只是普通用户权限的我们是如何得以修改 /etc/shadow 文件的?答案是 setuid。

setuid 位(八进制表示为 4000),如果将其应用于可执行文件,会将有效用户ID(effective user ID)从真实用户(实际执行程序的用户)ID更改为程序属主的有效用户ID。

大多数情况下,少数超级用户的程序才会做此设置。当普通用户执行 setuid root 程序时,该程序将以超级用户的权限来执行,可以访问普通用户通常被禁止访问的文件和目录。这显然会带来安全隐患,因此允许设置 setuid 位的程序数量必须控制在最小范围内。

# chmod u+s <程序文件名>
# 八进制法表示为
# chmod 4755 <程序文件名>

权限:-rwsr-xr-x,注意属主的s

setgid 位

setgid 位类似于 setuid 位,它会将有效组ID(effective group ID)从真实用户的真实组 ID(real group ID)更改为文件属主的有效组 ID。

如果对目录设置 setgid 位,那么在该目录下新创建的文件将由该目录的属组所有,而非文件创建者的属组所有。

这在共享目录中非常有用,当一个共同属组的成员需要访问目录中的所有文件时,不用管文件属主的属组是什么。

# chmod g+s <目录名>
# 八进制法表示为
# chmod 2775 <目录名>

权限:drwxrwsr-x,注意属主的 s

sticky 位

粘滞(sticky)位来自「远古」Unix 的遗留产物,用于将可执行文件标记为「不可交换」。

Linux 会忽略文件上设置的粘滞位,如果对目录设置了粘滞位,则能够阻止用户删除或者重命名其中的文件,除非用户是该目录的属主,或者是文件的属主,又或者是超级用户。

粘滞位常用来控制对共享目录(如 /tmp)的访问。

# chmod +t <目录名>
# 八进制法表示为
# chmod 1777 <目录名>

权限:drwxrwxrwt,注意最后的t

chown:修改文件的属主与属组

chown 命令用于修改文件的属主和属组。

同样也可以使用 -R 递归选项。

# 修改文件的属主
# chown <目标属主> <文件名>

# 在用户组前加上冒号即为修改文件的属组,属主不变
# chown :<目标属组> <文件名>

# 将以上结合,修改目录 wwwroot 的属主为 nginx,属组为 web
# -R 选项用于递归修改目录下的子文件及子目录
# chown -R nginx:web wwwroot