Linux 中用户与用户组

用户标识符

每个用户至少都有两个 ID,用户 ID(UID,User ID)和用户组 ID(GID,Group ID)。

当显示文件属性时,系统会根据 /etc/passwd/etc/group 文件的内容找到 UID/GID 对应的账号与组名再显示出来。

用户账号

用户通过终端或 SSH 登录时,系统的处理过程如下:

  1. 首先在 /etc/passwd 中查找是否存在输入的账户,如果存在,则读取对应的 UID、GID、主目录和 shell 设置。
  2. 核对输入的密码是否与 /etc/shadow 记录匹配。
  3. 如果账户和密码都正确,就可以进入 shell。

/etc/passwd 文件结构

passwd 文件中以行为单位记录系统中所有账号,各字段之间用冒号分隔开:

[root@101c7 bin]$ head -4 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

以上以第一条为例,总共七个字段,说明如下:

编号 内容 说明
1 root 账号名称,用来对应 UID。
2 x 密码,早期 UNIX 用来存放加密过的密码字段。
3 0 UID,其中 0 固定为 root 用,1-499 号留给系统账号用,500 之后为一般用户。
4 0 GID,组信息保存在 /etc/group 中。
5 root 用户信息说明列,只是用来解释账号意义。
6 /root 用户主文件夹位置。
7 /bin/bash 默认使用的 shell。如果是 /sbin/nologin 代表不能登录。

/etc/shadow 文件结构

shadow 文件中保存了密码和相关限制设置:

[root@101c7 bin]$ cat /etc/shadow
root:$6$A7YdIFXQJ47yq0::0:99999:7:::
bin:*:17632:0:99999:7:::

以第一条记录为例,总共有九个字段,说明如下:

编号 内容 说明
1 root 账户名。
2 7YdIFXQJ47yq0 编码过的密码,使用不同编码方式产生的长度不同。
3 13400 最近改动密码的日期,以 1970/01/01 作为基准计算经过时间。
4 0 密码不可被改动的天数,0 无限制,11 表示每次修改密码的等待间隔为 11 天。
5 99999 密码过期的期限天数,如果超过这个限制天数没改密码,密码会变为已过期。
6 7 密码过期前发出警告的提前天数。
7 14 密码过期后的账号宽限时间。
8 14800 账号失效日期,过了限制日期后账号无法再使用。
9 - 保留字段。

用户组

用户组可以将账户集中在一起组成一个逻辑排列,从而简化特权管理。和用户组有关的文件记录在 /etc/group/etc/gshadow 中。

/etc/group 文件结构

group 文件记录 GID 与组名的对应:

[root@101c7 bin]$ cat /etc/group
root:x:0:
bin:x:1:
daemon:x:2:

以第一条记录为例,总共有四个字段,说明如下:

编号 内容 说明
1 root 用户组名。
2 x 用户组密码,不再使用。
3 0 用户组 ID。
4 - 此用户组支持的账号名称。

初始用户组(initial group)与有效用户组(effective group):

  • 保存在 /etc/passwd 中的用户对应 GID 就是初始用户组。
  • 保存在 /etc/group 中的用户名说明用户在此组中,该组是组内用户的有效用户组。

/etc/gshadow 文件结构

gshadow 文件用来设定组密码:

[root@101c7 bin]$ cat /etc/gshadow
root:::
bin:::

文件内容和 /etc/group 差不多,除了第二列用来记录组密码。

两种群组机制

针对创建用户时是否创建私有组的策略有两种机制:

  • 私有群组机制

    系统会创建一个与账号同名的群组作为初始群组,且主文件夹权限设置为 700,这样对用户来说保密性较好。使用这一机制的代表有 RHEL、Fedora、CentOS 等。

  • 公共群组机制

    新建账户时若未指定组,系统会自动将 GID=100 分配给用户作为初始群组。此组为 users 公共组,主文件夹权限为 755,同一组内的用户可以共享主文件夹内的数据。SuSE 等发行版使用这一机制。

新增用户

使用默认设置新建用户时,系统所进行的操作如下:

  1. /etc/passwd 中创建一行与账号相关的数据,包括创建 UID、GID、主文件夹等;
  2. /etc/shadow 中将账号密码相关参数填入,默认无密码;
  3. /etc/group 中加入一个与账户名相同的组名;
  4. /home 目录下创建与账户同名的目录作为用户主文件夹,权限设置为 700。

可以通过 useradd -D 命令查看创建用户时使用的默认值:

[root@101c7 bin]$ useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

实际上,这是调用了 /etc/default/useradd 文件的内容。各变量的说明如下:

设置 说明
1 GROUP=100 设置新用户的初始组为 users,在 CentOS 中不适用。
2 HOME=/home 用户主文件夹的基准目录(basedir)。
3 INACTIVE=-1 密码过期后是否会失效的设置值。
4 EXPIRE= 账号失效的日期,YYYY-MM-DD 格式。
5 SHELL=/bin/bash 新用户默认的 shell 路径。
6 SKEL=/etc/skel 新用户主目录里默认的内容参考来源。
7 CREATE_MAIL_SPOOL=yes 创建用户的邮件信箱。

其他一些设置,如密码策略、邮箱目录等,存放在 /etc/login.defs 文件中:

[root@101c7 bin]$ cat /etc/login.defs | grep -v -E "^$|^#"
MAIL_DIR        /var/spool/mail
PASS_MAX_DAYS   99999
PASS_MIN_DAYS   0

/etc/login.defs 文件中,一些重要参数的说明如下:

选项 说明
1 MAIL_DIR 用户邮箱所在位置
2-6 PASS_, WARN_AGE 密码设置相关
7-14 UID, SYS_UID, GID, SYS_GID 设置 UID/GID 号相关参数
15 CREATE_HOME 建立用户主文件夹
16 UMASK 用户主文件夹的权限设置
17 USERGROUPS_ENAB 删除用户时,如果同名组是空组,也一并删除
18 ENCRYPT_METHOD 密码加密方式

修改密码

root 在修改密码时不需要输入旧密码,可以忽略密码规则。通常,普通用户在修改密码时需要输入旧密码,且密码需要符合复杂性要求。

密码管理机制由 /etc/pam.d/passwd 控制,密码测试模块使用 pam_cracklib.so

可以使用 authconfig 命令查看密码哈希使用的算法:

[root@101c7 ~]$ authconfig --test | grep hashing
password hashing algorithm is sha512

假设作为一般用户,原始密码为 A2345678b,则修改密码时的错误示例如下:

密码规则 错误示例
长度>8 b2345C
不是回文(即上次密码的倒置) b8765432A
不能和上次密码只有大小写区别 a2345678B
至少包含字母和数字 abababab
简单的轮询检查 2345678bA

PAM 模块

PAM(可插拔身份验证模块)是一套应用程序编程接口(API),用于提供一系列身份验证机制。通过告知 PAM 验证阶段的要求,PAM 能够返回验证结果(成功或失败)给用户。

PAM 只是一套验证机制,并可供其他程序调用,因此无论使用哪个程序,都可以使用 PAM 进行身份验证。

例如,passwd 命令调用 PAM 的过程如下:

  1. 用户执行 /usr/bin/passwd 程序并输入密码;
  2. passwd 调用 PAM 模块进行验证;
  3. PAM 模块在 /etc/pam.d/ 中查找与 passwd 程序同名的配置文件;
  4. 根据 /etc/pam.d/passwd 中的设置,逐步引用相关的 PAM 模块进行验证分析;
  5. 将验证结果返回给 passwd 程序;
  6. passwd 根据 PAM 返回的结果决定下一步操作(通过或要求重试)。

查看 /etc/pam.d/passwd 文件内容如下:

[root@101c7 ~]$ cat /etc/pam.d/passwd
#%PAM-1.0
auth       include      system-auth
account    include      system-auth
password   substack     system-auth
-password   optional    pam_gnome_keyring.so use_authtok
password   substack     postlogin

每一行都包含三个字段,分别是验证类别(type)、控制标志(flag)以及相应的 PAM 模块及其参数。

验证类型

验证类型(Type)有四种,分别为:

  • auth

    authentication(认证)的缩写,主要用于检验用户的身份信息,通常需要密码来进行验证,因此后续接的模块用于验证用户的身份。

  • account

    account(账号)主要用于授权,用于检验用户是否具有正确的授权。例如,在使用一个过期的密码进行登录时,将无法成功登录。

  • session

    session(会话)管理用户在登录期间(或使用特定命令期间)PAM 提供的环境设置。该类型通常用于记录用户登录和注销的信息。例如,在使用 sudo 命令时,会在安全日志中记录与 PAM 相关的信息,如 session open、session close 等信息。

  • password

    password(密码)用于进行密码验证和修改密码等相关操作。

这四种验证类型通常按照顺序进行。首先进行身份验证(auth),然后进行授权(account),接着记录会话信息(session),最后进行密码相关的操作(password)。

控制标志

控制标志(Control Flag)用于控制验证的方式。该字段指定了验证的通过标准,有以下四种控制标志:

  • required

    若验证成功,则返回 success 标志;若验证失败,则返回 failure 标志。无论成功或失败,都将继续后续的验证流程。由于后续的验证流程可以继续进行,因此这是最常用的标志之一,也方便记录日志。

  • requisite

    验证失败会立即返回原始程序,并带有 failure 标志,同时终止后续的验证流程。验证成功则带有 success 标志,并继续后续的验证流程。与 required 标志的最大区别在于,遇到失败时立即终止验证流程,因此无法记录失败产生的 PAM 信息。

  • sufficient

    若验证成功,则立即返回 success 给原始程序,并终止后续的验证流程。验证失败则带有 failure 标志,并继续后续的验证流程。与 requisite 标志正好相反。

  • optional

    optional 标志通常用于显示信息,而不是用于验证。

如果控制标志字段中出现 include,表示调用后面的文件作为该类别的验证配置。

模块

模块存放路径:

路径 说明
/etc/pam.d/* 每个程序单独的 PAM 配置文件。
/lib/security/* PAM 模块文件实际放置位置。
/etc/security/* 其他 PAM 环境配置文件。
/usr/share/doc/pam-*/ 详细的 PAM 说明文件。

一些比较常用的模块:

模块名 说明
pam_securetty.so 限制系统管理员 root 只能从安全的终端机登录,例如 tty1-7(由 /etc/securetty 设定)。
pam_nologin.so 限制一般用户能否登录主机。当 /etc/nologin 文件存在时,所有一般用户均无法登录。
pam_selinux.so SELinux 是针对程序来进行详细管理权限的功能。
pam_console.so 需要使用特殊的终端接口登录主机时,这个模块帮助处理一些文件权限的问题。
pam_loginuid.so 验证用户的 UID 数值,可以使用这个模块来规范。
pam_env.so 用来设置环境变量的一个模块。
pam_unix.so 用于验证阶段的认证功能,可以用于授权阶段的账号许可证管理、日志记录等。
pam_pwquality.so 用来验证密码的强度,包括密码是否在字典中、密码最大重试次数等。
pam_cracklib.so 用来检验密码强度,已被 pam_pwquality.so 取代。
pam_limits.so ulimit 命令用到了这个模块。

另外一个比较常用的是 /etc/security/limits.conf 这个配置文件,可以直接修改这个文件来对用户的系统使用配额做一些设置。

例如修改用户 user1 只能新建小于 100MB 的文件(hard),且大于 80MB 会警告(soft):

[root@101c7 ~]$ vim /etc/security/limits.conf 
#<domain>      <type>  <item>         <value>
#
#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4
user1            soft    fsize           80000
user1            hard    fsize           100000
"/etc/security/limits.conf" 64L, 2499C written

使用 ulimit 查询,并使用 dd 命令测试:

[user1@101c7 ~]$ ulimit -a | grep 'file size'
core file size          (blocks, -c) 0
file size               (blocks, -f) 80000
[user1@101c7 ~]$ dd if=/dev/zero of=filetest bs=1M count=200
File size limit exceeded
[user1@101c7 ~]$ ll -k filetest
-rw-rw-r--. 1 user1 user1 81920000 Sep 13 11:23 filetest

例如限制用户组 group1 每次只能有一个用户登录系统(maxlogins):

[root@101c7 ~]$ vim /etc/security/limits.conf 
#<domain>      <type>  <item>         <value>
@group1          hard    maxlogins       1

登录相关日志文件存放目录有 /var/log/secure/var/log/messages。如果发生任何无法登录或是产生意外错误,由 PAM 模块将数据记录在 /var/log/secure 中。