# 3.3.用户和基本账户管理

FreeBSD 允许多个用户同时使用计算机。尽管同一时间只能有一个用户坐在屏幕前使用键盘，但任意数量的用户都可以通过网络登录系统。为了使用系统，每位用户都应拥有自己的用户账户。

本章将介绍：

* FreeBSD 系统中不同类型的用户账户；
* 如何添加、删除和修改用户账户；
* 如何设置资源访问限制，以控制用户和用户组的权限；
* 如何创建用户组，并将用户添加为组成员。

## 3.3.1. 账户类型

由于访问 FreeBSD 系统的所有操作都必须通过账户完成，且所有进程均由用户启动，因此用户与账户管理至关重要。

FreeBSD 中主要有三类账户：系统账户、用户账户，以及超级用户账户。

### 3.3.1.1. 系统账户

系统账户用于运行诸如 DNS、邮件和 Web 服务器等服务。这样做的原因是出于安全考虑；如果所有服务都以超级用户身份运行，它们将可以不受限制地执行操作。

系统账户的例子如 `daemon`、`operator`、`bind`、`news` 和 `www`。

`nobody` 是一个通用的非特权系统账户。然而，使用 `nobody` 的服务越多，该用户关联的文件和进程就越多，从而其潜在权限也逐渐提升。

### 3.3.1.2. 用户账户

用户账户是分配给真实用户的，用于登录和使用系统。每位访问系统的人都应拥有一个唯一的用户账户。这样可以使管理员了解每位用户的操作，并防止用户之间相互干扰配置。

每位用户可以通过配置默认 shell、编辑器、按键绑定和语言设置等方式，设置适合自己的系统使用环境。

FreeBSD 系统中的每个用户账户都包含以下信息：

**用户名**\
用户名是在 `login:` 提示符处输入的标识。每个用户必须拥有唯一的用户名。创建合法用户名的规则详见 [passwd(5)](https://man.freebsd.org/cgi/man.cgi?query=passwd\&sektion=5\&format=html)。建议使用不超过八个字符且全部小写的用户名，以保持对旧应用程序的兼容性。

**密码**\
每个账户都需要设置密码。

**用户 ID（UID）**\
用户 ID 是用于在 FreeBSD 系统中唯一标识该用户的数字。支持用户名参数的命令会首先将其转换为 UID。建议使用小于 65535 的 UID，因部分软件可能对更大的 UID 兼容性不佳。

**组 ID（GID）**\
组 ID 是用于唯一标识用户所属主要用户组的数字。组是一种机制，通过 GID（而非 UID）来控制对资源的访问。这可显著减小部分配置文件的体积，并允许用户同时属于多个组。建议使用不超过 65535 的 GID，因更高的 GID 可能会导致某些软件运行异常。

**登录类（Login class）**\
登录类是组机制的扩展，用于在面向不同用户时提供更大的灵活性。相关内容将在 [配置登录类](https://docs.freebsd.org/en/books/handbook/security/#users-limiting) 中进一步讨论。

**密码变更时间**\
默认情况下，密码不会过期。但也可以为每个用户单独启用密码过期策略，强制其在一段时间后更改密码。

**账户过期时间**\
FreeBSD 默认不会使账户过期。如需创建具有使用期限的账户（例如学校中的学生账户），可使用 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 命令指定账户过期时间。若过期，该账户将无法登录，但其目录和文件仍会保留。

**用户全名**\
用户名是 FreeBSD 用于识别账户的唯一标识，但不一定反映用户的真实姓名。类似注释字段，该信息可以包含空格、大写字符，并超过八个字符。

**家目录**\
家目录是系统中某个目录的完整路径，是用户登录系统后的起始位置。通常的做法是将所有用户的家目录放在 `/home/用户名` 或 `/usr/home/用户名` 下。用户可在其家目录中存储个人文件和子目录。

**用户 shell**\
shell 是用户与系统交互的默认环境。存在多种 shell 类型，有经验的用户通常会有自己的偏好，可以通过账户设置进行配置。

### 3.3.1.3. 超级用户账户

超级用户账户通常称为 `root`，用于以无限制权限管理系统。因此，**不应**将其用于日常任务，例如收发邮件、浏览系统和编程。

与其他用户账户不同，超级用户可以无所限制地操作系统，若误用可能造成严重后果。普通用户的权限则受限，不太可能意外破坏整个系统。因此建议用户使用普通账户进行日常操作，仅在某个命令需要额外权限时再切换为超级用户。

使用超级用户身份执行命令时应三思而后行，多次确认命令内容，因为一个多余的空格或漏掉的字符都可能导致数据无法恢复。

获取超级用户权限有多种方式。虽然可以直接以 `root` 身份登录，但强烈不推荐这么做。

更好的方式是使用 [su(1)](https://man.freebsd.org/cgi/man.cgi?query=su\&sektion=1\&format=html) 命令切换为超级用户。如果在执行时指定了 `-` 参数，用户还会继承 root 用户的环境。执行此命令的用户必须属于 `wheel` 组，否则命令会失败。此外，还必须知道 `root` 用户的密码。

下面的示例中，用户仅为了运行 `make install` 而临时切换为超级用户。完成后，输入 `exit` 即可退出超级用户身份并返回普通用户权限。

**示例 1：以超级用户身份安装程序**

```sh
% configure
% make
% su -
Password:
# make install
# exit
%
```

内建的 [su(1)](https://man.freebsd.org/cgi/man.cgi?query=su\&sektion=1\&format=html) 框架适合单一系统或由一位管理员管理的小型网络。另一个选择是安装 [security/sudo](https://cgit.freebsd.org/ports/tree/security/sudo/) 软件包或 port。该软件支持操作记录，并允许管理员配置哪些用户可以以超级用户身份运行哪些命令。

## 3.3.2. 管理账户

FreeBSD 提供了多种不同的命令来管理用户账户。最常用的命令已在 [管理用户账户的工具](https://docs.freebsd.org/en/books/handbook/basics/#users-modifying-utilities) 中总结，后面还附有一些使用示例。更多细节和使用示例请参考每个工具的手册页。

**表 1. 管理用户账户的工具**

| 命令                                                                                          | 概要                  |
| ------------------------------------------------------------------------------------------- | ------------------- |
| [adduser(8)](https://man.freebsd.org/cgi/man.cgi?query=adduser\&sektion=8\&format=html)     | 推荐用于添加新用户的命令行应用程序。  |
| [rmuser(8)](https://man.freebsd.org/cgi/man.cgi?query=rmuser\&sektion=8\&format=html)       | 推荐用于删除用户的命令行应用程序。   |
| [chpass(1)](https://man.freebsd.org/cgi/man.cgi?query=chpass\&sektion=1\&format=html)       | 用于更改用户数据库信息的灵活工具。   |
| [passwd(1)](https://man.freebsd.org/cgi/man.cgi?query=passwd\&sektion=1\&format=html)       | 用于更改用户密码的命令行工具。     |
| [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html)               | 可修改用户账户所有方面的强大灵活工具。 |
| [bsdconfig(8)](https://man.freebsd.org/cgi/man.cgi?query=bsdconfig\&sektion=8\&format=html) | 带有账户管理支持的系统配置工具。    |

### 3.3.2.1. 添加用户

推荐使用的添加新用户的程序是 [adduser(8)](https://man.freebsd.org/cgi/man.cgi?query=adduser\&sektion=8\&format=html)。添加新用户时，此程序会自动更新 `/etc/passwd` 和 `/etc/group`。它还会为新用户创建 home 目录，从 `/usr/share/skel` 复制默认配置文件，并可选地向新用户发送一封欢迎邮件。此工具必须由超级用户运行。

[adduser(8)](https://man.freebsd.org/cgi/man.cgi?query=adduser\&sektion=8\&format=html) 是交互式的，会逐步引导创建新用户账户。如 [在 FreeBSD 上添加用户](https://docs.freebsd.org/en/books/handbook/basics/#users-modifying-adduser) 所示，输入所需信息或按 <kbd>Return</kbd> 接受方括号中的默认值。在此示例中，用户被邀请加入 `wheel` 组，使其可以通过 [su(1)](https://man.freebsd.org/cgi/man.cgi?query=su\&sektion=1\&format=html) 成为超级用户。完成后，该工具会提示是创建另一个用户还是退出。

**示例 2. 在 FreeBSD 上添加用户**

```sh
# adduser
```

输出应类似如下：

```sh
Username: jru
Full name: J. Random User
Uid (Leave empty for default):   # UID（留空以使用默认值）
Login group [jru]:               # 登录组
Login group is jru. Invite jru into other groups? []: wheel
Login class [default]:          # 登录类
Shell (sh csh tcsh zsh nologin) [sh]: zsh
Home directory [/home/jru]:     # home 目录
Home directory permissions (Leave empty for default):  # home 目录权限（留空使用默认）
Use password-based authentication? [yes]:             # 使用基于密码的认证？
Use an empty password? (yes/no) [no]:                 # 使用空密码？
Use a random password? (yes/no) [no]:                 # 使用随机密码？
Enter password:                 # 输入密码
Enter password again:          # 再次输入密码
Lock out the account after creation? [no]:            # 创建后锁定账户？
Username   : jru
Password   : ****
Full Name  : J. Random User
Uid        : 1001
Class      :
Groups     : jru wheel
Home       : /home/jru
Shell      : /usr/local/bin/zsh
Locked     : no
OK? (yes/no): yes
adduser: INFO: Successfully added (jru) to the user database.
Add another user? (yes/no): no
Goodbye!
```

> **注意**
>
> 由于输入密码时不会回显，请在创建用户账户时小心不要输错密码。

### 3.3.2.2. 删除用户

要从系统中彻底删除某用户，请以超级用户身份运行 [rmuser(8)](https://man.freebsd.org/cgi/man.cgi?query=rmuser\&sektion=8\&format=html)。该命令会执行以下步骤：

1. 删除该用户的 [crontab(1)](https://man.freebsd.org/cgi/man.cgi?query=crontab\&sektion=1\&format=html) 项（若有）。
2. 删除该用户的所有 [at(1)](https://man.freebsd.org/cgi/man.cgi?query=at\&sektion=1\&format=html) 任务。
3. 向该用户的所有进程发送 SIGKILL 信号。
4. 从系统本地密码文件中删除该用户。
5. 删除该用户的 home 目录（如果其归用户所有），包括处理通往实际 home 目录路径中的符号链接。
6. 从 `/var/mail` 中删除属于该用户的邮件文件。
7. 从 `/tmp`、`/var/tmp` 和 `/var/tmp/vi.recover` 中删除所有属于该用户的文件。
8. 从 `/etc/group` 中所有该用户所属的组中移除用户名。（如果某个组为空，且组名与用户名相同，则该组也会被删除；这是对 [adduser(8)](https://man.freebsd.org/cgi/man.cgi?query=adduser\&sektion=8\&format=html) 为每个用户创建唯一组的补充。）
9. 删除该用户拥有的所有消息队列、共享内存段和信号量。

[rmuser(8)](https://man.freebsd.org/cgi/man.cgi?query=rmuser\&sektion=8\&format=html) 不能用于删除超级用户账户，因为这几乎总是意味着严重破坏。

默认情况下，该命令以交互模式运行，如下所示：

**示例 3. `rmuser` 交互式删除账户**

```sh
# rmuser jru
```

输出应类似如下：

```sh
Matching password entry:
jru:*:1001:1001::0:0:J. Random User:/home/jru:/usr/local/bin/zsh
Is this the entry you wish to remove? y
Remove user's home directory (/home/jru)? y
Removing user (jru): mailspool home passwd.
```

### 3.3.2.3. 更改用户信息

所有用户都可以使用 [chpass(1)](https://man.freebsd.org/cgi/man.cgi?query=chpass\&sektion=1\&format=html) 更改其默认 shell 和账户的个人信息。超级用户可以用此工具更改任意用户的额外账户信息。

若不带参数（或仅带可选用户名），[chpass(1)](https://man.freebsd.org/cgi/man.cgi?query=chpass\&sektion=1\&format=html) 会显示一个编辑器用于更改用户信息。用户退出编辑器时，用户数据库将更新为新的信息。

> **注意**
>
> 除非以超级用户身份运行，否则该工具在退出编辑器时会提示输入用户密码。

在 [以超级用户身份使用 `chpass`](https://docs.freebsd.org/en/books/handbook/basics/#users-modifying-chpass-su) 一节中，超级用户输入了 `chpass jru`，正在查看可更改的字段。若 `jru` 自己运行该命令，仅会显示后六个字段供编辑。这在 [以普通用户身份使用 `chpass`](https://docs.freebsd.org/en/books/handbook/basics/#users-modifying-chpass-ru) 中展示。

**示例 4. 以超级用户身份使用 `chpass`**

```sh
# chpass jru
```

输出应类似如下：

```sh
# 修改 jru 的账户信息数据库
Login: jru
Password: *
Uid [#]: 1001
Gid [# or name]: 1001
Change [month day year]:       # 密码更改日期
Expire [month day year]:       # 账户过期日期
Class:
Home directory: /home/jru
Shell: /usr/local/bin/zsh
Full Name: J. Random User
Office Location:               # 办公地点
Office Phone:                  # 办公电话
Home Phone:                    # 家庭电话
Other information:             # 其他信息
```

**示例 5. 以普通用户身份使用 `chpass`**

```sh
# 修改 jru 的账户信息数据库
Shell: /usr/local/bin/zsh
Full Name: J. Random User
Office Location:               # 办公地点
Office Phone:                  # 办公电话
Home Phone:                    # 家庭电话
Other information:             # 其他信息
```

> [chfn(1)](https://man.freebsd.org/cgi/man.cgi?query=chfn\&sektion=1\&format=html) 与 [chsh(1)](https://man.freebsd.org/cgi/man.cgi?query=chsh\&sektion=1\&format=html) 是 [chpass(1)](https://man.freebsd.org/cgi/man.cgi?query=chpass\&sektion=1\&format=html) 的链接命令，[ypchpass(1)](https://man.freebsd.org/cgi/man.cgi?query=ypchpass\&sektion=1\&format=html)、[ypchfn(1)](https://man.freebsd.org/cgi/man.cgi?query=ypchfn\&sektion=1\&format=html) 和 [ypchsh(1)](https://man.freebsd.org/cgi/man.cgi?query=ypchsh\&sektion=1\&format=html) 也是。由于 NIS 支持是自动的，无需在命令前加 `yp`。NIS 配置方法见 [网络服务器](https://docs.freebsd.org/en/books/handbook/network-servers/#network-servers)。

### 3.3.2.4. 更改用户密码

任何用户都可以使用 [passwd(1)](https://man.freebsd.org/cgi/man.cgi?query=passwd\&sektion=1\&format=html) 轻松更改密码。为防止意外或未经授权的更改，该命令在设置新密码前会提示输入原密码：

**示例 6. 更改自己的密码**

```sh
% passwd
```

输出应类似如下：

```sh
Changing local password for jru.
Old password:                  # 输入旧密码
New password:                  # 输入新密码
Retype new password:           # 再次输入新密码
passwd: updating the database...
passwd: done
```

超级用户可以通过指定用户名来更改任意用户的密码。以超级用户身份运行该工具时，不会提示输入当前密码。这可用于用户忘记原密码时更改密码。

**示例 7. 以超级用户身份更改其他用户密码**

```sh
# passwd jru
```

输出应类似如下：

```sh
Changing local password for jru.
New password:                  # 输入新密码
Retype new password:           # 再次输入新密码
passwd: updating the database...
passwd: done
```

> 与 [chpass(1)](https://man.freebsd.org/cgi/man.cgi?query=chpass\&sektion=1\&format=html) 一样，[yppasswd(1)](https://man.freebsd.org/cgi/man.cgi?query=yppasswd\&sektion=1\&format=html) 也是 [passwd(1)](https://man.freebsd.org/cgi/man.cgi?query=passwd\&sektion=1\&format=html) 的链接命令，因此 NIS 与这两个命令都兼容。

### 3.3.2.5. 创建、删除、修改和显示系统用户与组

[pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 工具可用于创建、删除、修改和显示用户与组。它是系统用户和组文件的前端。[pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 提供了非常强大的命令行选项，适合用于 shell 脚本，但对于新用户来说可能比本节中的其他命令更复杂。

## 3.3.3. 管理用户组

一个用户组是一组用户的列表。一个用户组通过其组名和 GID 来标识。在 FreeBSD 中，内核通过进程的 UID 和其所属的用户组列表来判断该进程被允许执行哪些操作。在大多数情况下，某个用户或进程的 GID 通常指的是该列表中的第一个用户组。

组名与 GID 的映射关系记录在 `/etc/group` 中。这个文件是一个纯文本文件，包含四个用冒号分隔的字段。第一个字段是组名，第二个字段是加密密码，第三个字段是 GID，第四个字段是成员的逗号分隔列表。完整的语法描述请参考 [group(5)](https://man.freebsd.org/cgi/man.cgi?query=group\&sektion=5\&format=html)。

超级用户可以使用文本编辑器修改 `/etc/group`，不过建议使用 [vigr(8)](https://man.freebsd.org/cgi/man.cgi?query=vigr\&sektion=8\&format=html) 进行编辑，因为它可以捕捉一些常见错误。另一种方式是使用 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 来添加和编辑用户组。例如，要添加一个名为 `teamtwo` 的用户组并确认其存在：

> **警告**
>
> 使用 operator 用户组时必须格外小心，因为这可能会授予意想不到的类似超级用户的权限，包括但不限于关机、重启，以及访问该组在 `/dev` 中的所有条目。

示例 8：使用 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 添加用户组

```sh
# pw groupadd teamtwo
# pw groupshow teamtwo
```

输出应类似如下：

```sh
teamtwo:*:1100:
```

在这个例子中，`1100` 是 `teamtwo` 的 GID。此时，`teamtwo` 还没有成员。以下命令将会添加 `jru` 作为 `teamtwo` 的成员。

**示例 9：使用** [**pw(8)**](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) **将用户账户添加到一个新用户组中**

```sh
# pw groupmod teamtwo -M jru
# pw groupshow teamtwo
```

输出应类似如下：

```sh
teamtwo:*:1100:jru
```

传递给 `-M` 的参数是一个以逗号分隔的用户列表，用于添加到一个新的（空的）用户组中，或者用于替换现有用户组的全部成员。对用户而言，这种组成员资格不同于密码文件中列出的主用户组（且是额外的）。这意味着使用 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 的 `groupshow` 时不会显示该用户，但通过 [id(1)](https://man.freebsd.org/cgi/man.cgi?query=id\&sektion=1\&format=html) 或类似工具查询信息时则会显示。当使用 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 将用户添加到组中时，它仅操作 `/etc/group`，不会从 `/etc/passwd` 读取其他数据。

**示例 10：使用** [**pw(8)**](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) **向组中添加新成员**

```sh
# pw groupmod teamtwo -m db
# pw groupshow teamtwo
```

输出应类似如下：

```sh
teamtwo:*:1100:jru,db
```

在这个例子中，传递给 `-m` 的参数是一个以逗号分隔的用户列表，这些用户将被添加进组中。与前一个示例不同，这些用户是追加添加的，并不会替换已有用户。

**示例 11：使用** [**id(1)**](https://man.freebsd.org/cgi/man.cgi?query=id\&sektion=1\&format=html) **来判断用户组成员资格**

```sh
% id jru
```

输出应类似如下：

```sh
uid=1001(jru) gid=1001(jru) groups=1001(jru), 1100(teamtwo)
```

在这个例子中，`jru` 是 `jru` 和 `teamtwo` 这两个用户组的成员。

关于该命令和 `/etc/group` 格式的更多信息，请参阅 [pw(8)](https://man.freebsd.org/cgi/man.cgi?query=pw\&sektion=8\&format=html) 和 [group(5)](https://man.freebsd.org/cgi/man.cgi?query=group\&sektion=5\&format=html)。
