# 4.8 权限

文件系统权限机制是类 UNIX 系统安全架构的基石。通过为文件和目录配置适当的访问权限，系统可以实现对资源的受控访问，保障系统的安全性与完整性。这一机制遵循最小权限原则（least privilege principle）。

## 权限表达式

首先，我们观察以下 `ls` 命令的输出示例，以理解权限表达式的构成：

```sh
# ls -al /home/ykla  # 显示 /home/ykla 目录下的详细文件列表
total 74
drwxr-xr-x  17 ykla ykla    27 Mar 19 17:57 .
drwxr-xr-x   3 root wheel    4 Mar 19 16:05 ..
drwx------   4 ykla ykla     4 Mar 10 16:21 .mozilla
-rw-r--r--   1 ykla ykla   966 Feb 24 12:18 .profile
-rw-------   1 ykla ykla   200 Mar 19 17:57 .sh_history
-rw-r--r--   1 ykla ykla  1003 Feb 24 12:18 .shrc
drwxr-xr-x   2 ykla ykla     2 Mar  9 23:48 .themes
drwxr-xr-x   2 ykla ykla     2 Mar  9 20:45 桌面
```

再观察：

```sh
----------   1 root wheel         0 Mar 19 22:26 test
```

FreeBSD 文件访问权限可以用 10 个标志位来表示（请读者数一数第一列是否为 10 位），而这 10 个标志位由 4 个部分组成：

用斜杠分隔：`-/---/---/---`

```
- / --- / --- / ---
|   |     |     |
|   |     |     └─── 其他用户权限（others）
|   |     └───────── 同组用户权限（group）
|   └─────────────── 所有者权限（owner）
└─────────────────── 文件类型 / 设备类型
```

第一部分是第 1 位，用 `d` 表示目录，`-` 表示普通文件，`l` 表示符号链接文件，`b` 表示块设备文件，`p` 表示管道文件，`c` 表示字符设备文件，`s` 表示套接字文件。

第二部分是第 2、3、4 位，用于标识文件所属用户对文件的访问权限，用 `rwx` 表示读、写、执行权限（对于目录来说即访问权限，如 `ls`、`cd`），无权限则写成 `-`。

第三部分是第 5、6、7 位，用于标识文件所属组成员对文件的访问权限。

第四部分是第 8、9、10 位，用于标识其他用户对文件的访问权限。

读、写、执行权限除了用 `rwx` 表示外，也可以分别对应为数字 4、2、1，无权限即 0。每三位权限对应的数字相加后，组合在一起，就形成 3 位数字的表示方式。（记忆口诀：“读 4 写 2 执行 1”）。

如：

| 字符标识权限     | 数字标识权限 | 说明                                          |
| ---------- | ------ | ------------------------------------------- |
| -rwxrwxrwx | 777    | 所有人都可读、写、执行的普通文件                            |
| -rwxr-xr-x | 755    | 这是一个普通文件，所属用户有读、写、执行权限；同组用户和其他用户只能读或执行，不可写入 |

> **思考题**
>
> > `drw-------`，即 `600`，这是一个目录，只有所属用户可以读、写。
>
> 上面的说法正确吗，有意义吗，为什么？读者如何理解这种设计上的逻辑悖论？

> **技巧**
>
> 关于上面数字代表权限的代码可以在 [main/sys/sys/stat.h](https://github.com/freebsd/freebsd-src/blob/main/sys/sys/stat.h) 找到，由 IEEE Std 1003.1 所规范：
>
> ```c
> #define	S_IRWXU	0000700			/* 拥有者的读、写、执行（RWX）权限掩码 */
> #define	S_IRUSR	0000400			/* 拥有者的读（Read）权限 */
> #define	S_IWUSR	0000200			/* 拥有者的写（Write）权限 */
> #define	S_IXUSR	0000100			/* 拥有者的执行（Execute）权限 */
> ```

## `chmod` 命令

### 操作符方式

赋予所有用户对 test.sh 脚本的执行权限：

```sh
$ chmod a+x test.sh
```

在 `a+x` 中：

* `a` 表示操作对象为所有用户。可选项还有：`u` 表示所属用户，`g` 表示所属组，`o` 表示其他用户，若省略则依照系统默认对象操作；
* `+` 是操作符。意为增加权限。而可选项 `-` 则是移除权限；
* `rwx` 是权限模式。`r` 意为读、`w` 即写、`x` 执行。可选项 `s` 表示在文件执行时将进程的属主或属组设置为文件的属主或属组。

### 数字方式

设置 `test.sh` 的权限为：所有者可读写执行，组用户可读执行，其他用户无权限：

```sh
$ chmod 750 test.sh
```

其中：

* `7`：所属用户拥有读、写、执行的权限
* `5`：同组用户有读和执行的权限
* `0`：其他用户则没有任何权限

此处，选项 `-R` 可递归修改权限。

示例：

```sh
# chmod -R 777 /tmp # 允许任何用户读、写、执行 /tmp 目录下所有文件
# chmod -R a+rwx /tmp # 允许任何用户读、写、执行 /tmp 目录下所有文件
```

## `chown` 命令

用于修改文件的属主，包括所属用户和所属组。

示例：

* 修改 `t.sh` 属主为 `test1`

```sh
# chown test1 t.sh
```

* 修改 `t.sh` 的属主为用户 `test1`、组 `test`

```sh
# chown test1:test t.sh
```

* 修改 `/tmp` 目录下所有文件的属主为用户 `test1`、组 `test`：

```sh
# chown -R test1:test /tmp
```

此处，选项 `-R` 可递归修改属主。

## 课后习题

1. 在 FreeBSD 中创建 5 个测试文件，分别使用字符方式和数字方式设置不同权限组合，验证并记录结果。
2. 查看 FreeBSD 内核中权限检查的核心源码，尝试使其更加细粒度。
3. 修改 FreeBSD 中某个系统目录的默认权限配置，验证其行为变化。
