Skip to main content

第5章 用户身份与文件权限

章节简述

Linux 是一个以多用户、多任务并行处理著称的操作系统,以其卓越的稳定性和安全性闻名。但是,在幕后保障 Linux 系统的安全则涉及一系列复杂的配置工作。本章将详细讲解文件的所有者、所属组以及其他人对文件进行的读(r)、写(w)、执行(x)等操作的权限设置,此外,还将介绍如何在 Linux 系统中添加、删除和修改用户账户信息。

我们将探讨如何使用 SUID、SGID 和 SBIT 等特殊权限更加灵活地设置系统权限,从而突破仅依靠一般操作权限设置文件权限时的局限性,实现更精细化、更贴合复杂场景需求的权限管理。使用隐藏权限功能为系统增加一层隐形的防护盾,即使黑客能查看关键日志信息,也无法篡改或删除。而文件访问控制列表(Access Control List,ACL)进一步让单一用户或用户组对特定文件或目录进行特殊权限设置,从而实现满足工作需求的最小权限原则。

本章最后还会讲解如何使用su 命令与 sudo 服务,让普通用户具备管理员的权限,这不仅能够满足日常的工作需求,还能确保系统的安全性。

5.1 用户身份与能力

受到 20 世纪 70 年代计算机发展的影响,Linux 系统的设计初衷之一就是为了满足多个用户同时工作的需求,因此必须具备很好的安全性,尤其要确保单个服务的故障不会影响到整台服务器。在第 1 章中,我们学习了如何安装 Linux 系统,并特别强调了设置 root 管理员密码的重要性。这个 root 管理员就是存在于所有类 UNIX 系统中的超级用户,相当于 Windows 系统中的 administrator。它拥有最高的系统所有权,能够管理系统的各项功能,如添加/删除用户、启动/关闭服务进程、开启/禁用硬件设备等。

虽然以 root 管理员的身份工作时不会受到系统的限制,但正如俗话所说:“能力越大,责任越大。”一旦使用这个高能的 root 管理员权限执行了错误的命令,可能会直接毁掉整个系统。使用与否,确实需要好好权衡一下。

在学习过程中是否应使用 root 管理员权限来控制整个系统呢?对此,网络上有许多文章建议以普通用户的身份操作,这种方法更为安全,也更“无责任”。今天就要冒天下之大不韪给出自己的心得—强烈推荐大家在学习时使用root 管理员权限!

这种为 root 管理员正名的决绝态度在网络中应该是很罕见的,我之所以力荐 root 管理员权限,原因很简单。在 Linux 的学习过程中,如果使用普通用户身份进行操作,则在配置服务之后出现错误时,很难判断是系统自身的问题还是权限不足所致,这无疑会给大家的学习过程徒增坎坷。何况我们的实验环境是使用 VMware 虚拟机软件搭建的,可以将安装好的系统设置为一次快照,这样即便系统彻底崩溃,也可以在 5s 内快速还原出一台全新的系统,而不用担心数据丢失。

总之,刘遄老师在培训时都推荐每位学生使用 root 管理员权限来学习 Linux 系统,等到实际工作时再根据生产环境决定使用哪个用户权限—这更多是选择问题,而非技术性问题。

此外,许多图书或培训机构的老师会提到,Linux 系统中的管理员就是 root。这其实是错误的,Linux 系统的管理员之所以是 root,并不是因为它的名字叫 root,而是因为用户标识符UID(User IDentification)的数值为 0。在 Linux 系统中,UID 就像我们的身份证号码一样具有唯一性,因此可通过用户的 UID 值来判断用户身份。在 RHEL 10 系统中,用户身份有下面这些。

管理员(UID 为 0):系统的管理员用户。

系统用户(UID 为 1~999):为了避免某个服务程序的漏洞被黑客利用,Linux 系统默认由权限受限的独立系统用户来运行服务程序,从而有效限制可能的破坏范围。

普通用户(UID 从 1000 开始):由管理员创建的用于日常工作的用户。

需要注意的是,UID 是不能冲突的,而且管理员创建的普通用户的 UID 默认是从 1000开始的(即使前面有闲置的号码)。

为了方便管理属于同一组的用户,Linux 系统中还引入了用户组的概念。借助于用户组标识符(GID,Group IDentification),可以把多个用户加入同一个组中,从而方便为组中的用户统一规划权限或指定任务。假设一个公司中有多个部门,每个部门中又有很多员工,如果只想让员工访问本部门内的资源,就可以针对部门(而非具体的员工)来设置权限。例如, 对技术部门设置权限,使得只有技术部门的员工允许访问公司的数据库信息等。

另外,在 Linux 系统中创建每个用户时,将自动创建一个与其同名的基本用户组(Primary Group),而且这个基本用户组中只有该用户一个人。如果该用户以后被纳入其他用户组,则这个其他用户组会被称为附加用户组(Supplementary Group)。一个用户只有一个基本用户组,但是允许有多个附加用户组,从而满足日常的工作需要。

Tips :
基本用户组就像是原生家庭,是在创建账户(出生)时就自动生成的,终身只能有一个;而附加用户组则像工作单位,为了完成工作,需要加入到各个不同的群体中,这是需要手动添加的,可以有很多个。

1. id命令

id 命令用于显示用户的详细信息,语法格式为“id 用户名”。

这个 id 命令是一个在管理用户的整个过程中都需要用到的命令,因此建议仔细学习, 它能够简单轻松地查看用户的基本信息,例如用户ID、基本用户组与附加用户组 GID,以便于我们判别某个用户是否已经存在,以及查看相关信息。

下面使用 id 命令查看一个名称为 linuxprobe 的用户信息:

root@linuxprobe:~# id linuxprobe
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),10(wheel)

2. useradd命令

useradd 命令用于创建新的用户账户,语法格式为“useradd [参数] 用户名”。

使用 useradd 命令创建用户账户时,默认的用户家目录会被存放在/home 目录中,默认的 Shell 解释器为/bin/bash,而且默认会创建一个与该用户同名的基本用户组。这些默认设置可以根据表 5-1 中的 useradd 命令参数自行修改。

表5-1 useradd命令中的参数以及作用

参数作用
-d指定用户的家目录(默认为/home/username)
-e账户的到期时间,格式为YYYY-MM-DD.
-u指定该用户的默认UID
-g指定一个初始的用户基本组(必须已存在)
-G指定一个或多个扩展用户组
-N不创建与用户同名的基本用户组
-s指定该用户的默认Shell解释器

下面使用useradd 命令创建一个名称为linuxcool 的用户,并使用 id 命令确认信息:

root@linuxprobe:~# useradd linuxcool
root@linuxprobe:~# id linuxcool
uid=1001(linuxcool) gid=1001(linuxcool) groups=1001(linuxcool)

下面我们提高难度,创建一个普通用户并指定家目录的路径、用户的 UID 以及 Shell 解释器。在下面的命令中,请注意/sbin/nologin,它是终端解释器中的一员,与 Bash 解释器有着天壤之别。一旦用户的解释器被设置为 nologin,则代表该用户不能登录到系统中:

root@linuxprobe:~# useradd -d /home/linux -u 8888 -s /sbin/nologin linuxdown
root@linuxprobe:~# id linuxdown
uid=8888(linuxdown) gid=8888(linuxdown) groups=8888(linuxdown)

3. groupadd命令

groupadd 命令用于创建新的用户组,语法格式为“groupadd [参数] 群组名”。为了更加高效地指派系统中各个用户的权限,在工作中常常会把几个用户加入到同一个

组中,这样便可以针对一类用户统一安排权限。例如在工作中成立一个部门组,当有新的同事加入时就把他的账户添加到这个部门组中,这样新同事的权限就自动跟其他同事一模一样了,从而省去了一系列烦琐的操作。

创建用户组的步骤非常简单,例如使用如下命令创建一个用户组 winston:

root@linuxprobe:~# groupadd winston

4. usermod命令

usermod 命令用于修改用户的属性,英文全称为 user modify,语法格式为“usermod [参数] 用户名”。

前文曾反复强调,Linux 系统中的一切都是文件,因此在系统中创建用户也就是修改配置文件的过程。用户的信息保存在/etc/passwd 文件中,可以直接用文本编辑器来修改其中的用户参数项目,亦可以用 usermod 命令修改已经创建的用户信息,比如用户的 UID、基本/附加用户组、默认终端等。usermod 命令的参数以及作用如表 5-2 所示。

表 5-2 usermod 命令中的参数以及作用

参数作用
-c填写用户账户的备注信息
-d -m参数-m 与参数-d 连用,可重新指定用户的家目录并自动把旧的数据转移过去
-e账户的到期时间,格式为 YYYY-MM-DD
-g变更所属用户组
-G变更附加用户组
-L锁定用户禁止其登录系统
-U解锁用户,允许其登录系统
-s变更默认终端
-u修改用户的 UID

大家不要被这么多参数吓坏了。先来看一下账户linuxprobe 的默认信息:

root@linuxprobe:~# id linuxprobe
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),10(wheel)

然后将用户linuxprobe 加入到root 用户组中,这样附加用户组列表中则会出现root用户组的字样,而基本用户组不会受到影响:

root@linuxprobe:~# usermod -G root linuxprobe
root@linuxprobe:~# id linuxprobe
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),0(root)

再来试试用-u 参数修改 linuxprobe 用户的 UID:

root@linuxprobe:~# usermod -u 9999 linuxprobe
root@linuxprobe:~# id linuxprobe
uid=9999(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),0(root)

除此之外,同学们最关心的肯定是如果把用户的解释器终端由默认的/bin/bash 修改为/sbin/nologin 后会有什么样的效果。我们来试试吧:

root@linuxprobe:~# usermod -s /sbin/nologin linuxprobe
root@linuxprobe:~# su - linuxprobe
This account is currently not available.

效果很直观!将用户的终端设置成/sbin/nologin 后,用户马上就不能登录了(切换身份也不行),但这个用户依然能够被某个服务所调用,管理某个具体的服务。这样的好处是当黑客通过这个服务成功入侵系统后,破坏的范围也仅仅局限于这个特定的服务,而不能使用这个用户身份登录到整台服务器上,从而尽可能地把损失降至最小。

5. passwd命令

passwd 命令用于修改用户的密码、过期时间等信息,英文全称为 password,语法格式为“passwd [参数] 用户名”。

普通用户只能使用 passwd 命令修改自己的系统密码,而 root 管理员则有权限修改其他所有人的密码。更酷的是,root 管理员在 Linux 系统中修改自己或他人的密码时不需要验证旧密码,这一点特别方便。既然 root 管理员能够修改其他用户的密码,就表示其完全拥有该用户的管理权限。passwd 命令中的参数以及作用如表 5-3 所示。

表 5-3 passwd 命令中的参数以及作用

参数作用
-l锁定用户,禁止其登录
-u解除锁定,允许用户登录
--stdin允许通过标准输入修改用户密码
-d使该用户可用空密码登录系统
-e强制用户在下次登录时修改密码
-S显示用户的密码是否被锁定,以及密码所采用的加密算法名称

要修改自己的密码,只需要输入命令后敲击回车键即可:

root@linuxprobe:~# passwd
New password: 此处输入密码值
Retype new password: 再次输入进行确认
passwd: password updated successfully

要修改其他人的密码,则需要先检查当前是否为 root 管理员权限,然后在命令后指定要修改密码的那位用户的名称:

root@linuxprobe:~# passwd linuxprobe
New password: 此处输入密码值
Retype new password: 再次输入进行确认
passwd: password updated successfully

如果觉得重复输入两次密码有些麻烦,可以使用--stdin 参数接收由管道符传入的标准输入信息,passwd 命令会将其作为指定用户的密码值—不仅方便,而且很适合在批处理脚本中进行调用。

root@linuxprobe:~# echo "NewPass0107" | passwd --stdin linuxprobe
Changing password for user linuxprobe.
passwd: all authentication tokens updated successfully.

假设你有位同事正在度假,而且假期很长,那么可以使用 passwd 命令禁止该用户登录系统,等假期结束回归工作岗位时,再使用该命令允许用户登录系统,而不是将其删除。这样既保证了这段时间内系统的安全,也避免了频繁添加、删除用户带来的麻烦。

root@linuxprobe:~# passwd -l linuxprobe
passwd: password changed.
root@linuxprobe:~# passwd -S linuxprobe
linuxprobe L 2025-03-13 0 99999 7 -1

在解锁时,记得也要使用管理员的身份;否则,如果普通用户也有锁定权限,系统肯定会乱成一锅粥:

root@linuxprobe:~# passwd -u linuxprobe
passwd: password changed.
root@linuxprobe:~# passwd -S linuxprobe
linuxprobe P 2025-03-13 0 99999 7 -1

6. userdel命令

userdel 命令用于删除已有的用户账户,英文全称为 user delete,语法格式为“userdel [参数] 用户名”。

如果确认某位用户后续不会再登录到系统中,则可以通过 userdel 命令删除该用户的所有信息。在执行删除操作时,该用户的家目录默认会保留下来,此时可以使用-r 参数将其删除。userdel 命令的参数以及作用如表 5-4 所示。

表 5-4 userdel 命令中的参数以及作用

参数作用
-f强制删除用户
-r同时删除用户及用户家目录

在删除一个用户时,一般会建议保留他的家目录数据,以免有重要的数据被误删除。所以在使用 userdel 命令时可以不加参数,写清要删除的用户名就行:

root@linuxprobe:~# userdel linuxprobe
root@linuxprobe:~# id linuxprobe
id: ‘linuxprobe’: no such user

虽然此时该用户已被删除,但家目录数据会继续存放在/home 目录中,等确认未来不再使用时将其手动删除即可:

root@linuxprobe:~# cd /home
root@linuxprobe:/home# ls
linuxcool linuxdown linuxprobe
root@linuxprobe:/home# rm -rf linuxprobe
root@linuxprobe:/home# ls
linuxcool linuxdown

原则上建议不要习惯性地添加-rf 参数,如果一定要彻底删除账户信息和家目录文件, 应当将删除操作拆解为两个独立的步骤:使用 userdel 命令删除用户账户;使用 rm 命令删除家目录文件,以此形成操作缓冲机制,避免因误操作导致数据不可逆丢失。就像夫妻吵架了,不要着急把两人的纪念品扔掉,要先冷静一下,如果后悔了,可以随时再回家(添加回账户),此时一切将照旧(文件资料还都在),没有任何损失。

5.2 文件权限与归属

在 Linux 系统中,每个文件都有归属的所有者和所属组,并且规定了文件的所有者、所 属组以及其他人对文件所拥有的可读(read,简写为 r)、可写(write,简写为 w)、可执行(execute,简写为 x)等权限。对于一般文件来说,权限比较容易理解:“可读”表示能够读取文件的实际内容;“可写”表示能够编辑、新增、修改、删除文件的实际内容;“可执行”则表示能够运行一个脚本程序。然而,对于目录文件来说,理解其权限设置就不那么容易了。很多资深 Linux 用户其实也没有真正搞明白。对于目录文件来说,“可读”表示能够读取目录内的文件列表;“可写”表示能够在目录内新增、删除、重命名文件;而“可执行”则表示能够进入该目录。

可读、可写、可执行权限对应的命令在文件和目录上是有区别的,具体可参考表 5-5。

表 5-5 可读、可写、可执行权限对应的命令在文件和目录上的区别

文件的可读、可写、可执行权限也可分别用数字 4、2、1 来表示,文件所有者、文件所属组及其他用户权限之间无直接关联,如表 5-6 所示。

表 5-6 文件权限的字符与数字表示

文件权限的数字表示法基于字符(rwx)权限计算而来,其目的是简化权限的表示方式。例如,若某个文件的权限为 7,则代表可读、可写、可执行(4+2+1);若权限为 6,则代表可读、可写(4+2)。我们来看一个例子。现在有这样一个文件,其所有者拥有可读、可写、可执行的权限,其文件所属组拥有可读、可写的权限;其他人只有可读的权限。那么,这个文件的权限就是 rwxrw-r--,数字法表示即为 764。不过大家千万别再将这 3 个数字相加, 计算出 7+6+4=17 的结果,这是小学的数学加减法,不是 Linux 系统的权限数字表示法,这 3 个权限之间没有互通关系。

下面以 rw-r-x-w-权限为例,介绍如何将字符权限转换为数字权限。首先,将每个字符替换为相应的数字,如图 5-1 所示。

图5-1 字符与数字权限转换示意图

减号是占位符,代表这里没有权限,在数字表示法中用 0 表示。也就是说,rw-转换后是 420,r-x 转换后是 401,-w-转换后是 020。然后,将这 3 组数字之间的每组数字进行相加,得出 652,这便是转换后的数字权限。

将数字权限转换回字符权限的难度相对来说就大一些了,这里以652 权限为例进行讲解。

首先,数字 6 是由 4+2 得到的,不可能是 4+1+1(因为每个权限只会出现一次,不可能同时有两个可执行[x]权限);数字 5 则是由 4+1 得到的;数字 2 是本身,没有权限即是空值 0。接下来按照表 5-6 所示的格式进行书写,得到 420401020 这样一串数字。有了这些信息,就可以把这串数字转换成字符了,如图 5-2 所示。

图5-2 数字与字符权限转换示意图

大家一定要心中牢记,文件的所有者、所属组和其他用户的权限之间无关联。不要写成rrwwx--- 的样子,一定要把 rwx 权限位对应到正确的位置,写成rw-r-x-w-。

Linux 系统的文件权限相当复杂,但是用途广泛,建议大家把它彻底搞清楚之后再学习下一节内容。现在来练习一下。请各位读者分别计算数字表示法权限 764、652、153、731 所对应的字符表示法权限,然后再把 rwxrw-r--、rw--w--wx、rw-r--r--转换成数字表示法。

我们利用上文讲解的知识,一起分析图 5-3 中所示的文件信息。

图5-3 通过ls命令查看到的文件属性信息

图 5-3 中包含了文件类型、访问权限、所有者(属主)、所属组(属组)、占用的磁盘大小、最后修改时间和文件名称等信息。通过分析可知,该文件的类型为普通文件,所有者权限为可读、可写(rw-),所属组权限为可读(r--),除此以外的其他人只有可读权限(r--),文件的磁盘占用大小是 34298 字节,最近一次的修改时间为 4 月 2 日的 0:23,文件的名称为 install.log。

排在权限前面的减号(-)是文件类型(减号表示普通文件),新手经常会把它跟“无权限”混淆。尽管在 Linux 系统中一切都是文件,但是不同的文件由于作用不同,因此类型也不尽相同(有一点像 Windows 系统的后缀名)。常见的文件类型包括普通文件(-)、目录文件(d)、链接文件(l)、管道文件(p)、块设备文件(b)以及字符设备文件(c)。

普通文件的范围特别广泛,如纯文本信息、服务配置信息、日志信息以及 Shell 脚本等,都属于普通文件。几乎在每个目录下都能看到普通文件(-)和目录文件(d)的身影。块设备文件(b)和字符设备文件(c)一般是指硬件设备,比如鼠标、键盘、光驱、磁盘等,在/dev/目录中最为常见。应该很少有人会对鼠标、键盘进行硬件级别的管理吧。

5.3 文件的特殊权限

在复杂多变的生产环境中,单纯设置文件的 rwx 权限无法满足对安全和灵活性的需求, 因此便有了 SUID、SGID 与SBIT 等特殊权限位。这是一种对文件权限进行设置的特殊功能,可以与一般权限同时使用,以弥补一般权限不能实现的功能。下面具体解释这 3 个特殊权限位的功能以及用法。

1. SUID

SUID 是一种对二进制程序进行设置的特殊权限,能够让二进制程序的执行者临时拥有所有者的权限(仅对拥有执行权限的二进制程序有效)。例如,所有用户都可以执行 passwd 命令来修改自己的密码,并将新密码保存到/etc/shadow 文件中。仔细查看这个文件就会发现它的默认权限是 000,也就是说除了 root 管理员以外,所有用户都没有查看或编辑该文件的权限。但是,在使用 passwd 命令时如果加上 SUID 特殊权限位,就可以让普通用户临时获得程序所有者的身份,把变更的密码信息写入 shadow 文件中。这很像在古装剧中见到的手持尚方宝剑的钦差大臣,他手持的尚方宝剑代表的是皇上的权威,因此可以惩 戒贪官,但这并不意味着他可以永远成为皇上。因此这只是一种有条件的、临时的特殊权 限授权方法。

查看 passwd 命令属性时发现所有者的权限由 rwx 变成了 rws,其中 x 改变成 s 就意味着该文件被赋予了 SUID 权限。另外可能有读者会好奇,如果原本的权限是 rw-呢?如果原先权限位上没有 x 执行权限,那么被赋予特殊权限后将变成大写的S。

root@linuxprobe:~# ls -l /etc/shadow
----------. 1 root root 1048 Mar 13 13:11 /etc/shadow
root@linuxprobe:~# ls -l /bin/passwd
-rwsr-xr-x. 1 root root 91616 Jun 24 2024 /bin/passwd

Tips :
加粗显示的字体用来告诫用户一定要小心这个权限,因为一旦某个命令文件被设置了SUID 权限,就意味着凡是执行该命令文件的人都可以临时获取文件所有者所对应的最高 权限。因此,千万不要将 SUID 权限设置到 vim、cat、rm 等命令上面!!!

2. SGID

SGID 特殊权限有两种应用场景:当对二进制程序进行设置时,能够让执行者临时获取文件所属组的权限;当对目录进行设置时,则是让目录内新创建的文件自动继承该目录原有用户组的名称。

SGID 的第一种功能是参考 SUID 而设计的,不同点在于执行程序的用户获取的不再是文件所有者的临时权限,而是获取到文件所属组的权限。举例来说,在早期的 Linux 系统中,/dev/kmem 是一个字符设备文件,用于存储内核程序要访问的数据,权限为:

cr--r----- 1 root system 2, 1 Feb 11 2024 kmem

大家看出问题了吗?除了 root 管理员或属于 system 组的成员外,所有用户都没有读取该文件的权限。由于平时需要查看系统的进程状态,为了能够获取进程的状态信息,可在用于查看系统进程状态的 ps 命令文件上增加 SGID 特殊权限位。下面查看ps 命令文件的属性信息:

-r-xr-sr-x 1 bin system 59346 Feb 11 2024 ps

这样一来,由于 ps 命令被增加了 SGID 特殊权限位,所以当用户执行该命令时,也就临时获取到了 system 用户组的权限,从而顺利地读取到了设备文件。

前文提到,每个文件都有其归属的所有者和所属组,当创建或传送一个文件后,这个文件就会自动归属于执行这个操作的用户(即该用户是文件的所有者)。如果现在需要在一个部门内设置共享目录,让部门内的所有人员都能够读取目录中的内容,那么就可以在创建部门共享目录后,在该目录上设置 SGID 特殊权限位。这样,部门内的任何人员在里面创建的任何文件都会归属于该目录的所属组,而不再是自己的基本用户组。此时,用到的就是 SGID 的第二个功能,即在某个目录中创建的文件自动继承该目录的用户组的名称(只可以对目录进行设置)。

root@linuxprobe:~# cd /tmp
root@linuxprobe:/tmp# mkdir testdir
root@linuxprobe:/tmp# ls -ald testdir
drwxr-xr-x. 2 root root 6 Mar 13 13:16 testdir
root@linuxprobe:/tmp# chmod -R 777 testdir
root@linuxprobe:/tmp# chmod -R g+s testdir
root@linuxprobe:/tmp# ls -ald testdir
drwxrwsrwx. 2 root root 6 Mar 13 13:16 testdir

在使用上述命令设置好目录的 777 权限(确保普通用户可以向其中写入文件),并为该目录设置了 SGID 特殊权限位后,马上切换至一个普通用户,尝试在该目录中创建文件,并查看新创建的文件是否会继承新创建的文件所在的目录的所属组名称:

root@linuxprobe:/tmp# su - linuxprobe
linuxprobe@linuxprobe:~$ cd /tmp/testdir
linuxprobe@linuxprobe:/tmp/testdir$ echo "linuxprobe.com" > test
linuxprobe@linuxprobe:/tmp/testdir$ ls -al test
-rw-r--r--. 1 linuxprobe root 15 Mar 13 13:16 test
linuxprobe@linuxprobe:/tmp/testdir$ exit

除了上面提到的 SGID 的这两个功能,再介绍两个与本节内容相关的命令:chmod 和 chown。

chmod 命令用于设置文件的一般权限及特殊权限,英文全称为 change mode,语法格式为“chmod [参数] 文件名”。

这是一个与文件权限的日常设置强相关的命令。例如,要把一个文件的权限设置为其所有者可读可写可执行、所属组可读可写、其他人没有任何权限,则相应的字符表示为rwxrw ,其对应的数字表示为 760。该命令的使用方法如图 5-4 所示。

图5-4 chmod命令使用示意图

root@linuxprobe:/tmp# cd ~
root@linuxprobe:~# ls -l anaconda-ks.cfg
-rw-------. 1 root root 1064 Mar 13 03:41 anaconda-ks.cfg
root@linuxprobe:~# chmod 760 anaconda-ks.cfg
root@linuxprobe:~# ls -l anaconda-ks.cfg
-rwxrw----. 1 root root 1064 Mar 13 03:41 anaconda-ks.cfg

chown 命令用于更改文件的所有者和所属组,英文全称为 change owner,语法格式为“chown [所有者]:[所属组] 文件名”。

chmod 和 chown 命令是用于修改文件属性和权限的最常用命令,它们还有一个特别的共性,就是针对目录进行操作时需要加上-R 参数来表示递归操作,即对目录内所有的文件进行整体操作。

下面使用“所有者:所属组”的格式把前面那个文件的所属信息轻松修改一下,变更后的效果如下:

root@linuxprobe:~# chown linuxprobe:linuxprobe anaconda-ks.cfg 
root@linuxprobe:~# ls -l anaconda-ks.cfg
-rwxrw----. 1 linuxprobe linuxprobe 1064 Mar 13 03:41 anaconda-ks.cfg

3. SBIT

现在,大学里的很多老师都要求学生将作业上传到服务器的特定共享目录中,但总是有几个“破坏分子”喜欢删除其他同学的作业,这时就要设置 SBIT(Sticky Bit)特殊权限位了(也可以称之为特殊权限位之粘滞位)。SBIT 特殊权限位可确保用户只能删除自己的文件,而不能删除其他用户的文件。换句话说,当对某个目录设置了 SBIT 粘滞位权限后,那么该目录中的文件就只能被其所有者执行删除操作了。

最初不知道是哪位非资深技术人员将 Sticky Bit 翻译成了“粘滞位”,刘遄老师更愿将其称为“保护位”,这既好记,又能立刻让人了解它的作用。RHEL 10 系统中的/tmp 作为一个共享文件的目录,默认已经设置了 SBIT 特殊权限位,因此除非是该目录的所有者,否则无法删除这里面的文件。

与前面所讲的 SUID 和SGID 权限显示方法不同,当目录被设置了SBIT 特殊权限位后, 文件的其他用户权限部分的 x 执行权限就会被替换成 t 或者 T—原本有 x 执行权限则写成 t,原本没有 x 执行权限则写成 T。

由下可知,/tmp 目录上的SBIT 权限默认已经存在,这体现为“其他用户”权限字段的权限变为rwt:

root@linuxprobe:~# ls -ald /tmp
drwxrwxrwt. 17 root root 4096 Oct 28 00:29 /tmp

其实,文件能否被删除并不取决于自身的权限,而是看其所在目录是否有写入权限(其原理会在下一章讲到)。为了避免现在很多读者不放心,下面的命令还是赋予了这个 test 文件最大的 777 权限(rwxrwxrwx):

root@linuxprobe:~# cd /tmp
root@linuxprobe:/tmp# echo "Welcome to linuxprobe.com" > test
root@linuxprobe:/tmp# chmod 777 test
root@linuxprobe:/tmp# ls -al test
-rwxrwxrwx. 1 root root 26 Mar 13 13:18 test

随后,切换到一个普通用户身份下,尝试删除这个由其他人创建的文件,这时就会发现, 即便可读、可写、可执行权限全部打开,但是由于 SBIT 特殊权限位的缘故,依然无法删除该文件:

root@linuxprobe:/tmp# su - linuxprobe
linuxprobe@linuxprobe:~$ cd /tmp
linuxprobe@linuxprobe:/tmp$ rm -f test
rm: cannot remove 'test': Operation not permitted

在工作中,若能善加使用特殊权限,就能实现很多巧妙的功能。使用 chmod 命令设置特殊权限的参数如表 5-7 所示。

表 5-7 SUID、SGID、SBIT 特殊权限的设置参数

参数作用
u+s设置 SUID 权限
u-s取消 SUID 权限
g+s设置 SGID 权限
g-s取消 SGID 权限
o+t设置 SBIT 权限
o-t取消 SBIT 权限

切换回 root 管理员的身份下,在家目录中创建一个名为 linux 的新目录,随后为其设置 SBIT 权限:

linuxprobe@linuxprobe:/tmp$ exit
root@linuxprobe:/tmp# cd ~
root@linuxprobe:~# mkdir linux
root@linuxprobe:~# chmod -R o+t linux
root@linuxprobe:~# ls -ld linux
drwxr-xr-t. 2 root root 6 Mar 13 13:19 linux

上述代码中的 o+t 参数是在一般权限已经设置完毕的前提下,又新增了一项特殊权限。如果我们想将一般权限和特殊权限一起设置,有什么高效率的方法吗?

其实,SUID、SGID 与 SBIT 也有对应的数字表示法,分别为 4、2、1。也就是说 777 还不是最大权限,最大权限应该是 7777,其中第 1 个数字代表的是特殊权限位。既然知道了数字表示法是由“特殊权限+一般权限”构成的,现在就以上面 linux 目录的权限为例,为大家梳理一下计算方法。

在 rwxr-xr-t 权限中,最后一位是 t,这说明该文件的一般权限为 rwxr-xr-x, 并带有 SBIT 特殊权限。对于可读(r)、可写(w)、可执行(x)权限的数字表示法大家应该很熟悉了—rwxr-xr-x 即 755,而 SBIT 特殊权限位是 1,则合并后的结果为 1755。

再增加点难度,如果权限是 rwsrwSr--呢?首先不要慌,大写 S 表示原先没有执行权限,因此一般权限为 rwxrw-r--,将其转换为数字表示法后结果是 764。带有 SUID 和SGID 特殊权限的数字法表示是 4 和 2,心算得出结果是 6,合并后的结果为 6764。这个示例确实难度大一些,大家可以参考图 5-5 的计算过程进行学习,在搞明白后再往下看。

图5-5 权限的字符表示法转数字表示法

将特殊权限的数字表示法转换成字符表示法的难度略微高一些,这里以 5537 为例讲解。首先,特殊权限的 5 是由 4+1 组成的,意味着有SUID 和SBIT。SUID 和SGID 的写法是, 原先有可执行权限则是小写s,如果没有可执行权限则是大写 S;而 SBIT 的写法则是,原先有可执行权限是小写 t,没有可执行权限是大写 T。一般权限的 537 进行字符转换后应为r-x-wxrwx,然后在此基础上增加SUID 和 SBIT 特殊权限,合并后的结果是 r-s-wxrwt。大家可以参考图 5-6 所示的计算过程来帮助理解。

图5-6 权限的数字表示法转字符标识法

Tips :
在 Linux 系统中,文件的权限位有点像北京的房价,寸土寸金,一个权限位竟能有这么多含义,大家工作中一定要小心谨慎。

5.4 文件的隐藏属性

Linux 系统中的文件除了具备一般权限和特殊权限之外,还有一种隐藏权限(即被隐藏起来的权限),默认情况下不能直接被用户发觉。有用户曾经在生产环境和 RHCE 考试题目中碰到过明明权限充足却无法删除某个文件的情况,或者仅能在日志文件中追加内容而不能修改或删除内容的情况,这在一定程度上阻止了黑客篡改系统日志的图谋,因此这种“奇怪” 的文件权限也保障了 Linux 系统的安全性。

既然叫隐藏权限,那么使用常规的 ls 命令肯定不能看到它的真面目。隐藏权限的专用设置命令是 chattr,专用查看命令是 lsattr。

1. chattr命令

chattr 命令用于设置文件的隐藏权限,英文全称为 change attributes,语法格式为“chattr [参数] 文件名称”。

如果想要把某个隐藏功能添加到文件上,则需要在命令后面追加“+参数”,如果想要把某个隐藏功能移出文件,则需要追加“-参数”。chattr 命令中可供选择的隐藏权限参数非常丰富,具体如表 5-8 所示。

表 5-8 chattr 命令中的隐藏权限参数及其作用

参数作用
i无法对文件进行修改;若对目录设置了该参数,则仅能修改其中的子文件内容,而不能新建或删除文件
a仅允许补充(追加)内容,无法覆盖/删除内容(Append Only)
S文件内容在变更后立即同步到磁盘(sync)
s彻底从磁盘中删除,不可恢复(用零块填充原文件所在磁盘区域)
A不再修改这个文件或目录的最后访问时间(Atime)
b不再修改文件或目录的存取时间
D检查压缩文件中的错误
d使用 dump 命令备份时忽略本文件/目录
c默认将文件或目录进行压缩
u当删除该文件后依然保留其在磁盘中的数据,方便日后恢复
t让文件系统支持尾部合并(tail-merging)
x可以直接访问压缩文件中的内容

为了让读者能够更好地见识隐藏权限的效果,我们先来创建一个普通文件,然后立即尝试删除(这个操作肯定会成功):

root@linuxprobe:~# echo "for Test" > linuxprobe
root@linuxprobe:~# rm linuxprobe
rm: remove regular file 'linuxprobe'? y

实践是检验真理的唯一标准。如果你没有亲眼见证过隐藏权限强大功能的美妙,就一定不会相信原来 Linux 系统会如此安全。接下来再次新建一个普通文件,并为其设置“不允许删除与覆盖”(+a 参数)权限,然后再尝试将这个文件删除:

root@linuxprobe:~# echo "for Test" > linuxprobe
root@linuxprobe:~# chattr +a linuxprobe
root@linuxprobe:~# rm linuxprobe
rm: remove regular file 'linuxprobe'? y
rm: cannot remove 'linuxprobe': Operation not permitted

可见,上述操作失败了。

2. lsattr命令

lsattr 命令用于查看文件的隐藏权限,英文全称为 list attributes,语法格式为“lsattr [参数] 文件名称”。

在 Linux 系统中,文件的隐藏权限必须使用 lsattr 命令来查看,平时使用的 ls 之类的命令看不出端倪:

root@linuxprobe:~# ls -al linuxprobe
-rw-r--r--. 1 root root 9 Mar 13 13:20 linuxprobe

一旦使用 lsattr 命令后,文件上被赋予的隐藏权限马上就会原形毕露:

root@linuxprobe:~# lsattr linuxprobe
-----a---------------- linuxprobe

此时按照显示的隐藏权限的类型(字母),使用 chattr 命令将其去掉:

root@linuxprobe:~# chattr -a linuxprobe
root@linuxprobe:~# lsattr linuxprobe
---------------------- linuxprobe
root@linuxprobe:~# rm linuxprobe
rm: remove regular file 'linuxprobe'? y

我们通常会将-a 参数设置到日志文件(如/var/log/messages)上,这样可在不影响系统正常写入日志的前提下,防止黑客擦除自己的作案证据。如果希望彻底地保护某个文件,不允许任何人修改和删除它的话,不妨加上-i 参数试试,效果特别好。

在美剧《越狱》的第一季中,主角迈克尔·斯科菲尔德把装有越狱计划的磁盘开窗扔进了湖中,结果在第二季被警探打捞出来恢复了数据,然后就有了第二季、第三季、第四季、第五季,有了他和哥哥的逃亡故事。所以,要想彻底删除某个文件,可以使用

+s 参数来保证其被删除后不可恢复—磁盘上的文件数据会被用零块重新填充,那就更保险了。

5.5 文件访问控制列表

不知道大家是否发现,前文讲解的一般权限、特殊权限、隐藏权限其实有一个共性—权限是针对某一类用户设置的,即对很多人同时生效。如果希望对某个指定的用户进行单独的精准权限控制,就需要用到文件的访问控制列表(ACL)了。通俗来讲,基于普通文件或目录设置 ACL 其实就是针对指定的用户或用户组设置文件或目录的操作权限,从而更加精准地派发权限。另外,如果针对某个目录设置了 ACL,则目录中的文件会继承其 ACL 权限;若针对文件设置了 ACL,则文件不再继承其所在目录的ACL 权限。

为了直观查看 ACL 对文件权限控制的强大效果,我们先切换到普通用户,然后尝试进入root 管理员的家目录中。在没有针对普通用户为 root 管理员的家目录设置 ACL 之前,其执行结果如下所示:

root@linuxprobe:~# su - linuxprobe
linuxprobe@linuxprobe:~$ cd /root
-bash: cd: /root: Permission denied
linuxprobe@linuxprobe:~$ exit

1. setfacl 命令

setfacl 命令用于管理文件的 ACL 权限规则,英文全称为 set file access control lists (ACL), 语法格式为“setfacl [参数] 文件名”。

ACL 权限提供的是在所有者、所属组、其他人的可读/可写/可执行权限之外的特殊权限控制。使用 setfacl 命令可以针对单一用户或用户组、单一文件或目录来进行可读/可写/ 可执行权限的控制。其中,针对目录文件需要使用-R 递归参数;针对普通文件则使用-m 参数;如果想要删除某个文件的 ACL,则可以使用-b 参数。setfacl 命令的常用参数以及作用如表 5-9 所示。

表 5-9 setfacl 命令的常用参数以及作用

参数作用
-m修改权限
-M从文件中读取权限
-x删除某个权限
-b删除全部权限
-R递归子目录

例如,我们原本无法进入/root 目录中,现在为普通用户单独设置一下权限:

root@linuxprobe:~# setfacl -Rm u:linuxprobe:rwx /root

随后再切换到这位普通用户的身份下,现在就能正常进入了:

root@linuxprobe:~# su - linuxprobe
linuxprobe@linuxprobe:~$ cd /root
linuxprobe@linuxprobe:/root$ ls
anaconda-ks.cfg Documents Music Public Videos
Desktop Downloads Pictures Templates
linuxprobe@linuxprobe:/root$ exit

是不是觉得效果很酷呢?但是现在有这样一个小问题—怎么去查看文件是否设置了ACL 呢?常用的 ls 命令是看不到 ACL 信息的,但是却可以看到文件权限的最后一个点(.) 变成了加号(+),这就意味着该文件已经设置了 ACL。现在大家是不是感觉学得越多,越不敢说自己精通 Linux 系统了吧?就这么一个不起眼的点(.),竟然还表示这么一种重要的权限。

root@linuxprobe:~# ls -ld /root
dr-xrwx---+ 14 root root 4096 Mar 13 13:22 /root

2. getfacl 命令

getfacl 命令用于查看文件的 ACL 权限规则,英文全称为 get file access control lists, 语法格式为“getfacl [参数] 文件名称”。

Linux 系统中的命令就是这么又可爱又好记。想要设置 ACL,用的是 setfacl 命令;要想查看 ACL,则用的是 getfacl 命令。下面使用 getfacl 命令显示在 root 管理员家目录上设置的所有 ACL 信息:

root@linuxprobe:~# getfacl /root
getfacl: Removing leading '/' from absolute path names
# file: root
# owner: root
# group: root
user::r-x
user:linuxprobe:rwx
group::r-x
mask::rwx
other::---

还可以针对某个用户组设置 ACL 权限。例如,允许某个组的用户读写/etc/fstab 文件:

root@linuxprobe:~# setfacl -m g:linuxprobe:rw /etc/fstab
root@linuxprobe:~# getfacl /etc/fstab
getfacl: Removing leading '/' from absolute path names
# file: etc/fstab
# owner: root
# group: root
user::rw-
group::r--
group:linuxprobe:rw-
mask::rw-
other::r--

设置错了想删除?没问题!要清空所有 ACL 权限,请用-b 参数;要删除某一条指定的权限,就用-x 参数:

root@linuxprobe:~# setfacl -x g:linuxprobe /etc/fstab
root@linuxprobe:~# getfacl /etc/fstab
getfacl: Removing leading '/' from absolute path names
# file: etc/fstab
# owner: root
# group: root
user::rw-
group::r--
mask::r--
other::r--

ACL 权限的设置都是立即且永久生效的,不需要再编辑什么配置文件,这一点特别方便。但是,这也带来了一个安全隐患,即如果不小心设置错了权限,就会覆盖掉文件原始的权限信息,并且永远都找不回来了。

操作前备份一下,总是好的习惯

例如,在备份/home 目录上的 ACL 权限时,可使用-R 递归参数,这样不仅能够把目录本身的权限进行备份,还能将里面的文件权限也自动备份。另外,再加上第 3 章学习过的输出重定向操作,可轻松实现权限的备份。需要注意,getfacl 在备份目录权限时不能使用绝对路径的形式,因此我们需要先切换到最上层根目录,然后再进行操作。

root@linuxprobe:~# cd /
root@linuxprobe:/# getfacl -R home > backup.acl
root@linuxprobe:/# ls -l backup.acl
-rw-r--r--. 1 root root 945 Mar 13 13:24 backup.acl

ACL 权限的恢复也很简单,使用的是--restore 参数。由于在备份时已经指定是对 /home 目录进行操作,所以不需要写对应的目录名称,它能够自动找到要恢复的对象:

root@linuxprobe:/# setfacl --restore backup.acl

5.6 su 命令与 sudo 服务

各位读者在实验环境中很少遇到安全问题,并且为了避免因权限因素导致配置服务失败, 建议使用 root 管理员的身份来学习本书。但是,在生产环境中,我们必须对安全保持敬畏之心,不要用 root 管理员身份去做所有事情。一旦执行了错误命令,可能会直接导致系统崩溃。这样一来,不但客户指责,领导批评,没准奖金也会鸡飞蛋打。但转念一想,尽管 Linux 系统为了安全性考虑,使得许多系统命令和服务只能被 root 管理员使用,但这也让普通用户受到了更多的权限束缚,导致无法顺利完成特定的工作任务。

su 命令可以解决切换用户身份的需求,使得当前用户在不退出登录的情况下,顺畅地切换到其他用户,比如从 root 管理员切换至普通用户:

root@linuxprobe:/# su - linuxprobe
linuxprobe@linuxprobe:~$ id
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

细心的读者一定会发现,上面的 su 命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。

另外,当从 root 管理员切换到普通用户时是不需要密码验证的,而从普通用户切换成 root 管理员就需要进行密码验证了,这也是一个必要的安全检查:

linuxprobe@linuxprobe:~$ su - root
Password: 此处输入管理员密码

尽管像上面这样使用 su 命令后,普通用户可以完全切换到 root 管理员的身份来完成相应工作,但这将暴露 root 管理员的密码,从而增大了系统密码被黑客获取的概率。这并不是最安全的方案。

接下来继续学习如何使用 sudo 命令把特定命令的执行权限赋予指定用户,这样既可保证普通用户能够完成特定的工作,也能避免泄露 root 管理员密码。我们要做的就是合理配置sudo 服务,以便兼顾系统的安全性和用户的便捷性。

Tips :
授权原则:在保证普通用户完成相应工作的前提下,尽可能少地赋予额外的权限。

sudo 命令用于给普通用户提供额外的权限来执行指定的命令,语法格式为“sudo [参数] 命令”。

使用 sudo 命令能够给普通用户提供额外的权限来完成原本只有 root 管理员才能完成的任务,还能限制用户执行指定的命令,记录用户执行过的每一条命令,集中管理用户与权限(/etc/sudoers),以及允许在验证密码后的一段时间内不再需要用户再次验证密码。sudo命令的常用参数以及作用如表 5-10 所示。

表 5-10 sudo 命令的常用参数以及作用

参数作用
-h列出帮助信息
-l列出当前用户可执行的命令
-u 用户名或 UID 值以指定的用户身份执行命令
-k清空密码的有效时间,下次执行 sudo 时需要再次进行密码验证
-b在后台执行指定的命令
-p更改询问密码的提示语

当然,如果担心直接修改配置文件会出现问题,推荐使用与 sudo 命令配套的 visudo 命令来配置用户权限。

visudo 命令用于编辑、配置用户 sudo 的权限文件,语法格式为“visudo [参数]”。该命令会自动调用 Vi 编辑器来配置/etc/sudoers 权限文件,能够解决多个用户同时

修改权限而导致的冲突问题。不仅如此,visudo 命令还可以对配置文件内的参数进行语法检查,并在发现参数错误时进行报错提醒。这要比用户直接修改文件更友好、安全、方便。

/etc/sudoers:1:7: syntax error
aaabbbcccddd
^
What now?

使用visudo 命令配置权限文件时,其操作方法与 Vim 编辑器中用到的方法完全一致, 因此在编写完成后记得在末行模式下保存并退出。在配置权限文件时,按照下面的格式在第101 行(大约)填写上指定的信息。

谁可以使用 允许使用的主机 = (以谁的身份) 可执行命令的列表

谁可以使用:稍后要为哪位用户进行命令授权。

允许使用的主机:填写 ALL 表示不限制来源的主机,也可填写如 192.168.10.0/24 这样的网段限制来源地址,使得只有从允许网段登录时才能使用 sudo 命令。

以谁的身份:填写 ALL 表示系统最高权限,也可以填写另外一位用户的名字。

可执行命令的列表:填写 ALL 表示不限制命令,也可填写如/usr/bin/cat 这样的文件名称来限制命令列表,多个命令文件之间用逗号(,)间隔。

在 Linux 系统中配置服务文件时,虽然没有硬性规定,但从经验来讲新增参数的位置不建议太靠上,以免我们新填写的参数在执行时失败,导致一些必要的服务功能没有成功加载。一般建议在配置文件中找一下相似的参数,然后在相邻位置进行新的修改,或者在文件的中下部位置进行添加修改。

root@linuxprobe:~# visudo
99 ## Allow root to run any commands anywhere
100 root ALL=(ALL) ALL
101 linuxprobe ALL=(ALL) ALL

在填写完毕后记得要先保存再退出,然后切换至指定的普通用户身份,此时就可以用sudo -l 命令查看所有可执行的命令了(在下面的命令中,验证的是普通用户的密码,而不是 root 管理员的密码,请读者不要搞混了):

root@linuxprobe:~# su - linuxprobe
linuxprobe@linuxprobe:~$ sudo -l

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.

For security reasons, the password you type will not be visible.

[sudo] password for linuxprobe:
Matching Defaults entries for linuxprobe on linuxprobe:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES",
env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User linuxprobe may run the following commands on linuxprobe:
(ALL) ALL
(ALL) ALL

接下来是见证奇迹的时刻!作为一名普通用户,是肯定不能看到 root 管理员的家目录 (/root)中的文件信息的,但是,只需要在想执行的命令前面加上sudo 命令就行了:

linuxprobe@linuxprobe:~$ ls /root
ls: cannot open directory '/root': Permission denied
linuxprobe@linuxprobe:~$ sudo ls /root
anaconda-ks.cfg Documents Music Public Videos
Desktop Downloads Pictures Templates

效果立竿见影!但是考虑到生产环境中不允许某个普通用户拥有整个系统中所有命令 的最高执行权(这也不符合前文提到的权限赋予原则,即尽可能少地赋予权限),ALL 参数就有些不合适了。因此只能赋予普通用户具体的命令以满足工作需求,这也受到了必要的 权限约束。如果需要让某个用户只能以 root 管理员的身份执行指定的命令,切记一定要给出该命令的绝对路径,否则系统无法识别。这时,先使用 whereis 命令找出命令所对应的保存路径:

linuxprobe@linuxprobe:~$ exit
root@linuxprobe:~# whereis cat
cat: /usr/bin/cat /usr/share/man/man1/cat.1.gz
root@linuxprobe:~# whereis reboot
reboot: /usr/sbin/reboot /usr/share/man/man2/reboot.2.gz /usr/share/man/man8/reboot.8.gz

然后使用 visudo 命令继续编辑权限文件,将原先第 101 行新增的参数作如下修改,且多个命令之间用逗号(,)间隔。

root@linuxprobe:~# visudo
99 ## Allow root to run any commands anywhere
100 root ALL=(ALL) ALL
101 linuxprobe ALL=(ALL) /usr/bin/cat,/usr/sbin/reboot

在编辑好后依然是先保存再退出。再次切换到指定的普通用户,然后尝试正常查看某个系统文件的内容,此时系统提示没有权限(Permission denied)。这时再使用 sudo 命令就能顺利地查看文件内容了:

root@linuxprobe:~# su - linuxprobe
linuxprobe@linuxprobe:~$ cat /etc/shadow
cat: /etc/shadow: Permission denied
linuxprobe@linuxprobe:~$ sudo cat /etc/shadow
root:$y$j9T$pg8bgLsCm0JreeO8laDHb8qW$cNPfXxGES.qDqkCTrpJUgM3GKju1jD3T9qQ1HMcxvr/::0:99999:7:::
bin:*:19898:0:99999:7:::
daemon:*:19898:0:99999:7:::
adm:*:19898:0:99999:7:::
lp:*:19898:0:99999:7:::
sync:*:19898:0:99999:7:::
shutdown:*:19898:0:99999:7:::
………………省略部分输出信息………………
linuxprobe@linuxprobe:~$ exit

大家千万不要以为到这里就结束了,刘遄老师还有更压箱底的宝贝。不知大家是否发觉在每次执行 sudo 命令后都会要求验证一下密码。虽然这个密码就是当前登录用户的密码, 但是每次执行 sudo 命令时都要输入一次密码其实也挺麻烦的,这时可以添加 NOPASSWD 参数,使得用户下次再执行 sudo 命令时不用密码验证:

root@linuxprobe:~# visudo
99 ## Allow root to run any commands anywhere
100 root ALL=(ALL) ALL
101 linuxprobe ALL=(ALL) NOPASSWD:/usr/bin/cat,/usr/sbin/reboot

这样,当切换到普通用户后再执行命令时,就不用再频繁地验证密码了,我们在日常工作中也就痛快至极了。

root@linuxprobe:~# su - linuxprobe
linuxprobe@linuxprobe:~$ reboot
User root is logged in on tty2.
Please retry operation after closing inhibitors and logging out other users.
Alternatively, ignore inhibitors and users with 'systemctl reboot -i'.
linuxprobe@linuxprobe:~$ sudo reboot

请同学们仔细留意上面的用户身份变换,visudo 命令只有 root 管理员才可以执行,普通用户在使用时会提示权限不足。

复习题

  1. 在 Linux 系统中,root 是谁?

    答:是 UID 为 0 的用户,是权限最大(责任也最大)、限制最小的管理员。

  2. 在 Linux 系统中添加和删除用户的命令分别是什么?

    答:添加和删除用户的命令分别是useradd 与userdel。

  3. 若某个文件的所有者具有文件的可读/可写/可执行权限,其余人仅有可读权限,那么用数字表示应该是什么?

    答:所有者权限为 rwx,所属组和其他人的权限为 r--,因此数字表示应该是 744。

  4. 某文件的字符权限为 rwxrw-r--,那么对应的数字权限应该是多少?

    答:数字权限应该是 764。

  5. 某链接文件的权限用数字表示为 755,那么相应的字符表示是什么呢?

    答:在 Linux 系统中,不同文件具有不同的类型,因此这里应写成lrwxr-xr-x。

  6. 如果希望用户执行某命令时临时拥有该命令所有者的权限,应该设置什么特殊权限?

    答:特殊权限中的 SUID。

  7. 若对文件设置了隐藏权限(+i 参数),则意味着什么?

    答:无法对文件进行修改;若对目录设置了该参数,则仅能修改其中的子文件内容而不能新建或删除文件。

  8. 使用访问控制列表(ACL)来限制 linuxprobe 用户组,使得该组中的所有成员不得在/tmp 目录中写入内容。

    答:想要设置用户组的 ACL,则需要把 u 改成 g,即 setfacl -Rm g:linuxprobe:r-x /tmp。

  9. 普通用户使用 sudo 命令时是否需要验证密码?

    答:系统在默认情况下需要验证当前登录用户的密码,若不想验证,可添加 NOPASSWD参数。

  10. 如何让名为 linuxprobe 的用户在使用 sudo 命令时不需要进行密码验证?请尝试写出参数。

    答:linuxprobe ALL=(ALL) NOPASSWD:ALL