一、Linux 是多用户系统

我们知道,任何操作系统都存在 “用户的概念” ,Linux 也不例外。

Linux 允许使用者在 Linux 系统上通过规划不同类型、不同层级的用户,并公平地分配系统资源与工作环境。

而与 Windows 系统最大的不同,在于 Linux 允许不同的用户同时登录主机,同时使用主机的资源,因此 Linux 被称为是多用户系统。

基于此,我们必须详细了解 Linux 对于用户用户组的规划,才能更好地理解 Linux 作为多用户、多任务系统的优势,也才能地使用 Linux 支持我们日常的开发工作。

 

二、用户与用户组的概念

Linux 作为多用户系统,如何区分不同用户对于文件的权限的问题成为了不可避免的问题。

例如,小 A 希望个人文件不被其他用户读取,而如果不对文件进行权限设置,共享了主机资源的小 B 也可以读取小 A 的个人文件,这是不合理的,不同用户对不同文件所拥有的权限应该不尽相同。

因此,Linux 以 “用户与用户组” 的概念,建立用户与文件权限之间的联系,保证系统能够充分考虑每个用户的隐私保护,很大程度上保障了 Linux 作为多用户系统的可行性。

或者说,“用户与用户组” 与文件权限息息相关。(关于文件权限的概念,会在下一篇文章进行讲解)

因此,从文件权限的角度出发,“用户与用户组” 引申为三个具体的对象——文件所有者用户组成员其他人。每一个对象对某一个文件的持有权限是不同的。

 

2.1、文件所有者(User)

当一个用户创建了一个文件,这个用户就是这个文件的文件所有者。文件所有者对文件拥有最高权限,同时排他性地拥有该文件。

换句话说,除非文件所有者开放权限,否则其他人无法对文件执行查看、修改等操作。

这也是 Linux 系统能够保护用户隐私的最关键的原因。

在文件所有者占有文件之后,需要文件所有者对其他用户开放权限,其他用户才能查看、修改文件。

如果仅区分 “文件所有者” 和 “其他用户”,那么文件所有者对其他用户开放权限后,所有其他用户均能查看、修改文件。

但是,若文件所有者希望仅对部分用户开放,那么仅仅区分 “用户所有者” 和 “其他用户” 显然不满足需求。

这就引入了 “用户组的概念”。

 

2.2、用户组成员(Group)

将 “其他用户” 区分为用户组成员和其他人后,若文件所有者希望对部分用户开放权限,而对其他人继续保持私有,则只需要将这部分用户与文件所有者划入一个用户组。

这样,这部分用户就成了与文件所有者同组的用户组成员。用户可以对用户组成员开放文件权限,用户组成员则具备了查看、修改文件的权限,而对其他无关用户保持私有。

用户组成员在团队开发中非常有帮助。

例如,团队成员之间保持文件资源共享,但对非团队成员保持私有,这就需要将文件所有者与团队成员用户划分为同一个用户组,再对用户组成员开放权限即可。

需要注意的是,一个用户可在多个用户组中

 

2.3、其他人(Others)

顾名思义,就是与文件所有者没有任何联系的其他用户。

 

2.4、具体例子

至此,我们知道了 Linux 系统下,每一个文件都具有 “文件所有者”、“用户组”、“其他人” 三种身份。

我们举一个具体例子,来详细地了解 “文件所有者”、“用户组”、“其他人” 这三个角色的含义。

假设有一个班级,有一名老师。老师根据自己编写的教案(老师的教案不能分享给其他任何人),指导本班同学共同完成一个黑板报任务。老师为本班同学提供了黑板,并允许本班同学能够查看、修改黑板上的内容,不允许非本班的学生查看、修改黑板上的内容。

我们将这个例子与 Linux 中 ”文件所有者“、”用户组成员“、”其他人“ 进行映射:

老师——教案和黑板的 ”文件所有者“

教室——用户组,老师和学生同属一个用户组

学生——用户组成员

非本班学生——其他人

教案不能分享给任何人——老师是 “文件所有者”,将 ”教案“ 的权限对其他所有人保持私有。

黑板允许班级学生修改,但是不允许非本班人员修改——老师是 “文件所有者”,将 “黑板” 的权限对用户组成员开放权限,而对非用户组成员保持私有

 

2.5、0号用户——root

在这里不得不提 Linux 系统中,具有最高权限的用户——root。

root 用户是系统中唯一的一个超级管理员,拥有了系统中的所有权限,可以执行任何想要执行的操作,也正因为如此,处于安全考虑,一般情况下不推荐使用 root 用户进行日常使用。

root 用户所在的用户组称为 “root组”,处于 root 组的普通用户,能够通过 sudo 命令获取 root 权限。该部分会在本文第四部分说明。

 

三、用户与用户组在 Linux 中的记录

Linux 将用户账号、密码等相关的信息分别存储在四个文件夹下:

  • /etc/passwd —— 管理用户UID/GID重要参数
  • /etc/shadow —— 管理用户密码
  • /etc/group —— 管理用户组相关信息
  • /etc/gshadow —— 管理用户组管理员相关信息

这些文件中,每一行代表一个用户或一个用户组,并存储了相关的用户或用户组信息。

 

3.1、/etc/passwd

该文件中,每一行的存储格式为:

账号名称 : 密码 : UID : GID : 用户信息说明列 : 主文件夹 : shell

root : x : 0 : 0 : root : /root : /bin/bash

其中,

密码项显示 “x” 是出于安全考虑,Linux 将密码信息移到 /etc/shadow 进行存储;

每一个用户都有一个UID、GID,对应的含义就是UserID、GroupID,UID 会映射到 /etc/shadow 以获得密码信息,GID 会映射到 /etc/group 以获取用户的用户组信息。

 

3.2、/etc/shadow

该文件中,每一行的存储格式为:

账号名称 : 密码 : 最近改动密码的日期 : 密码不可被改变的天数 : 密码需要重新更改的天数 : 更改提醒天数 : 密码过期后账号的宽限时间 : 账号失效日期 : 保留

root : (字符串,此处打码) : 200 : 0 : 99999 : 7 : : :

其中,

第二列表示密码加密后的字符串。

/etc/passwd 通过 UID,在该文件中找出对应 UID 的用户,并提取对应密码用于登陆验证。

 

3.3、/etc/group

该文件中,每一行的存储格式为:

用户组名称 : 用户组密码 : GID : 此用户组包含的账号名称

root : x : 0 : root

其中,

用户组密码通常是为了设置用户组管理员存在的,其信息也移动到 /etc/gshadow 中;

/etc/passwd 通过 GID,在该文件中找到对应的用户组,并提取用户组相关信息;

另外,由于一个用户可以在多个用户组中,因此就有一个初始用户组的有效用户组的概念。

所谓的初始用户组,就是用户所记录的 GID,是在创建用户时生成或指定的用户组;

所谓的有效用户组,就是利用命令 groups 查看并输出的首个用户组,即有效用户组;

用户在登录的时候,以初始用户组身份工作,用户可以用 newgrp 命令实现有效用户组的切换。

 

3.4、/etc/gshadow

该文件中,每一行的存储格式为:

用户组名 : 密码 : 用户组管理员账号 : 该用户组包含的账号名称

root : : : root

一般用户组不使用用户组管理员,相应地也就不需要设置密码。

 

四、Linux 用户账号管理

在此部分,会分别介绍新增、修改、删除用户及用户组,用户身份切换,查询用户信息等多种用户账号的管理操作。

 

4.1、新增、修改、删除用户

新增用户

  • useradd

useradd 可以用来新增用户,简要语法为:

useradd [options] [username]

在使用 useradd 时,可以通过不同的参数 options,达到不同的创建用户的效果,例如指定UID、指定初始用户组、指定次要用户组、指定主文件夹等。

具体参数请利用 man 命令进行查询。

useradd 在不指定任何参数的时候,会参考两个主要配置文件的默认值来新增用户

文件路径:/etc/default/useradd
GROUP = 100                                 # 默认的用户组
HOME = /home                                # 默认的主文件夹所在目录
INACTIVE = -1                               # 密码失效日
EXPIRE =                                        # 账号失效日
SHELL = /bin/shell                  # 默认shell
SKEL = /etc/skel                        # 用户主文件夹的内容数据参考目录
CREATE_MAIL_SPOOL = yes         # 是否创建邮件信箱


文件路径:/etc/login.defs
PASS_MAX_DAYS           99999               # 多久必须重设密码(天)
PASS_MIN_DAYS       0                       # 距上次修改密码多久不可重设密码(天)
PASS_MIN_LEN            5                       # 密码最短的字符长度
PASS_WARN_AGE           7                       # 距离多少天过期会报警提示
UID_MIN                     500                 # 创建用户的UID默认最小值
UID_MAX                     60000               # 创建用户的UID上限
GID_MIN                     500                 # 创建用户的GID默认最小值
GID_MAX                     60000               # 创建用户的GID上限
USERGROUPS_ENAB     yes                 # 删除用户时是否删除初始用户组(组内不再有其他成员)
MD5_CRYPT_ENAB      yes                 # 密码是否经过MD5加密

useradd 通过参考这两个文件的配置信息,赋予创建的用户默认值。

另外,useradd 默认不会在 /home 下创建用户同名的主目录;

同时,useradd 创建的用户还没有设置登录密码,需要利用passwd进行密码设置。

 

  • passwd

利用 passwd 命令,可以设置或重置密码

passwd [options] [username]

与 useradd 相同,不同的 options 参数能够满足不同的密码设置需求,包括失效时间、密码改动时间等。

具体请查询 passwd 命令的帮助手册。

 

  • adduser

adduser 与 useradd 的功能一样,都是为了创建新用户而存在的命令,但是 adduser 与 useradd 在一些方面存在不同。

  1. useradd 创建用户,但是不创建密码等其他用户信息,需要使用 passwd 设置密码才能使用;而 adduser 能通过交互界面,由用户直接输入密码等,设置用户信息。
  2. useradd 默认不在 /home 下创建用户同名的主文件夹,而 adduser 默认创建。
  3. useradd 是一个命令,而 adduser 被理解为一个 “简单的应用程序”。

在实用性上,adduser 确实要实用不少。

相似地,有 addgroup、deluder、delgroup 命令,与 adduser 的性质相似,下面不再赘述

修改用户

  • chage

chage 命令用来修改与用户密码相关的过期信息,如密码失效日、密码最短保留天数、失效前警告天数等。

chage [option] [username]

当然,passwd 也可以做相应的修改,有兴趣的读者可以仔细对比一下二者的区别。

 

  • usermod

usermod 命令用来修改用户信息。

usermod [options] [username]

usermod 通过选用不同的 options 参数,可以修改存储在 etc/passwd 内的用户信息。

删除用户

  • userdel

userdel 命令用来删除用户的相关的所有数据。

userdel [options] [username]
  • deluser

与 adduser 性质相似

 

4.2、新增、修改、删除用户组

新增用户组

  • groupadd

使用方式与 useradd 非常相似,与 useradd 不同的是,新建的用户组通常不需要设置密码。

groupadd [options] [groupname]
  • addgroup

与 adduser 性质相似。

修改用户组

  • groupmod

groupmod 命令用来修改 group 相关的参数,不过通常不建议修改 GID

groupmod [options] [groupname]

删除用户组

  • groupdel

groupdel 删除用户组之前,必须保证没有任何一个用户使用这个用户组作为初始用户组,否则无法删除

groupdel [options] [groupname]
  • delgroup

与 deluser 性质相似。

 

4.3、用户身份切换

前面说到,由于 root 用户具有系统所有权限,出于安全考虑,通常会以普通用户登录和使用 Linux。

但是在日常工作中,通常会碰到只有 root 用户才有权限执行的操作,这就需要使用用户身份切换的命令了。

涉及用户身份切换的命令有两个:su、sudo

 

su

su [options] [username]

options:
-:代表使用 login-shell 的变量文件读取方式来登录系统
-l:同上
-m:表示使用当前的环境设置,而不读取新用户的配置文件
-c:仅进行一次命令,执行完后直接回到目前的用户身份

如果 username 为空,则默认切换为 root 用户。

这里需要十分注意,options 中是否带 “-” 的区别是很大的

“su” 表示读取变量设置方式为 non-login shell,即切换身份但不读取目标用户的 shell 变量,因此很多变量不会发生改变,例如 PATH、MAIL 等重要变量,仍然保持切换前用户的变量信息。

“su -” 表示切换身份的同时读取目标用户的 login-shell ,通常建议使用这一方式切换身份。

完成工作后,可以以 exit 命令返回到原用户。

另外,在普通用户切换到 root 用户时,需要 root 用户的登录密码,才能成功切换。这里又涉及到一个安全问题,如何让指定的普通用户具备 root 权限的同时,不让其知道 root 的登录密码呢?这就需要使用 sudo 命令了。

 

sudo

普通用户可以通过 sudo 命令,使用 root 用户权限来执行命令。

当然,不是所有的用户都能执行 sudo 命令的,而是在 /etc/sudoers 文件内的用户才能执行这个命令。

sudo 的执行流程大致为:

  • 系统到 /etc/sudoers 下检查用户是否有执行 sudo 的权限
  • 若有 sudo 权限,则需要输入本用户的密码(root 用户执行 sudo 不需要密码)
  • 验证成功后执行命令

因此,关键在于执行 sudo 的用户是否存在于 /etc/sudoers 文件内。

我们不妨打开 sudoers 文件查看相关信息。

sudoers 文件

在 sudoers 文件中,我们发现两行关键信息

图中第一行,表示可执行 sudo 的单个用户白名单

root                                            ALL=(ALL:ALL)                                           ALL
用户账号            登录者来源主机名=(可切换身份:身份所在用户组)             可执行命令

图中第二行,表示可执行 sudo 的用户组白名单

root                                            ALL=(ALL:ALL)                                           ALL
用户账号            登录者来源主机名=(可切换身份:身份所在用户组)             可执行命令

通过修改 ”可切换身份“,可以限制用户执行 sudo 的目标身份;

通过修改 ”可执行命令“,可以限制用户利用 sudo 执行的命令内容,达到局部授权的作用。

以下为样例:

testuser            ALL=(ALL:ALL)                   ALL
testuser            ALL=(root:root)             ALL
testuser            ALL=(root:root)             /usr/bin/passwd

第一行表示 testuser 可以利用 sudo 以任何身份执行任何命令

第二行表示 testuser 仅可以以 root 身份执行任何命令

第三行表示 testuser 仅可以以 root 身份执行 passwd 命令

 

4.6、查询用户信息

涉及用户信息查询的命令主要有:

id <user>                           # 展示指定user的UID、GID、用户组信息等,默认为当前有效用户
who am i                            # 等同于 who -m,仅显示当前登录用户相关信息
whoami                              #   仅显示当前有效用户的用户名
w                                           # 展示当前正在登录主机的用户信息及正在执行的操作
who                                     # 展示当前正在登录主机的用户信息
last <user>                     # 展示指定用户的历史登录信息,默认为当前有效用户
lastlog -u <user>           # 展示指定用户最近的一次登录信息,默认显示所有用户

这里不再展示每个命令的效果。

有趣的是,who am i 命令与 whoami 命令在一些情景下不尽相同。对此,我会专门以一篇短文解释二者的小区别。

用户可以在不同的任务情景下,选择不同的命令查询用户的相关信息。

另外,每个命令都有各自可用的参数,支持不同的功能,这里也不再一一说明, 各位可以尝试用帮助命令去进行查看。