本文档中的所有示例都使用 root 权限操作,普通用户操作另行注释。在 Markdown 代码块中,命令描述将在前一行使用 # 表示。
回顾基本权限¶
众所周知,可以使用 ls -l
查看 GNU/Linux 的基本权限
Shell > ls -l
- rwx r-x r-x 1 root root 1358 Dec 31 14:50 anaconda-ks.cfg
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
1 2 3 4 5 6 7 8 9 10
它们的含义如下
部分 | 描述 |
---|---|
1 | 文件类型。- 表示这是一个普通文件。后面将介绍七种文件类型。 |
2 | 所有者用户的权限,rwx 的含义分别表示:读、写、执行。 |
3 | 所有者组的权限。 |
4 | 其他用户的权限。 |
5 | 子目录数量(包括 . 和 .. )。对于文件,它表示硬链接的数量,1 表示自身。 |
6 | 所有者用户名。 |
7 | 所有者组名。 |
8 | 对于文件,它显示文件大小。对于目录,它显示文件命名占用的固定值 4096 字节。要计算目录的总大小,请使用 du -sh |
9 | 最后修改日期。 |
10 | 文件名(或目录名)。 |
七种文件类型¶
文件类型 | 描述 |
---|---|
- | 表示一个普通文件。包括纯文本文件(ASCII);二进制文件(二进制);数据格式文件(数据);各种压缩文件。 |
d | 表示目录文件。默认情况下,每个目录中都包含一个 . 和 .. 。 |
b | 块设备文件。包括各种硬盘驱动器、USB 驱动器等等。 |
c | 字符设备文件。串行端口的接口设备,例如鼠标、键盘等。 |
s | 套接字文件。它是一种专门用于网络通信的文件。 |
p | 管道文件。它是一种特殊的文件类型,主要目的是解决多个程序同时访问一个文件时出现的错误。FIFO 是 first-in-first-out 的缩写。 |
l | 软链接文件,也称为符号链接文件,类似于 Windows 中的快捷方式。硬链接文件,也称为物理链接文件。 |
基本权限的含义¶
对于文件
数字表示 | 权限 | 描述 |
---|---|---|
4 | r(读) | 表示您可以读取此文件。您可以使用 cat 、head 、more 、less 、tail 等命令。 |
2 | w(写) | 表示可以修改文件。可以使用 vim 等命令。 |
1 | x(执行) | 可执行文件(例如脚本或二进制文件)的权限。 |
对于目录
数字表示 | 权限 | 描述 |
---|---|---|
4 | r(读) | 表示可以列出目录的内容,例如 ls -l 。 |
2 | w(写) | 表示您可以在此目录中创建、删除和重命名文件,例如 mkdir 、touch 、rm 等命令。 |
1 | x(执行) | 表示您可以进入目录,例如 cd 命令。 |
信息
对于目录,r 和 x 权限通常同时出现。
特殊权限¶
在 GNU/Linux 中,除了上面提到的基本权限外,还有一些特殊权限,我们将一一介绍。
ACL 权限¶
什么是 ACL?ACL(访问控制列表),目的是解决 Linux 下三种身份无法满足资源权限分配需求的问题。
例如,老师给学生上课,老师在 OS 的根目录下创建了一个目录。只允许这个班的学生上传和下载,其他人不允许。此时,目录的权限为 770。有一天,另一个学校的学生来听老师讲课,应该如何分配权限?如果你把这个学生放到 所有者组 中,他将拥有与这个班学生相同的权限 - rwx。如果将学生放入 其他用户,他将没有任何权限。此时,基本权限分配无法满足要求,需要使用 ACL。
Windows 操作系统中也有类似的功能。例如,要为用户分配文件权限,对于用户定义的目录/文件,**右键单击** ---> **属性** ---> **安全** ---> **编辑** ---> **添加** ---> **高级** ---> **立即查找**,找到相应的用户/组 ---> 分配特定权限 ---> **应用**,完成。
GNU/Linux 同样如此:将指定的用户/组添加到文件/目录,并授予相应的权限以完成 ACL 权限分配。
如何启用 ACL?您需要找到挂载点所在的设备的文件名及其分区号。例如,在我的机器上,您可以执行以下操作
Shell > df -hT
Filesystem Type Size Used Avail Use% Mounted on
devtmpfs devtmpfs 3.8G 0 3.8G 0% /dev
tmpfs tmpfs 3.8G 0 3.8G 0% /dev/shm
tmpfs tmpfs 3.8G 8.9M 3.8G 1% /run
tmpfs tmpfs 3.8G 0 3.8G 0% /sys/fs/cgroup
/dev/nvme0n1p2 ext4 47G 11G 35G 24% /
/dev/nvme0n1p1 xfs 1014M 187M 828M 19% /boot
tmpfs tmpfs 774M 0 774M 0% /run/user/0
Shell > dumpe2fs /dev/nvme0n1p2 | head -n 10
dumpe2fs 1.45.6 (20-Mar-2020)
Filesystem volume name: <none>
Last mounted on: /
Filesystem UUID: c8e6206d-2892-4c22-a10b-b87d2447a885
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
当您看到 **"Default mount options: user_xattr acl"** 行时,表示已启用 ACL。如果未启用,您也可以临时启用它 -- mount -o remount,acl /
。它也可以永久启用
Shell > vim /etc/fstab
UUID=c8e6206d-2892-4c22-a10b-b87d2447a885 / ext4 defaults,acl 1 1
Shell > mount -o remount /
# or
Shell > reboot
ACL 的查看和设置¶
要查看 ACL,您需要使用 getfacle
命令 -- getfacle FILE_NAME
如果您要设置 ACL 权限,则需要使用 setfacl
命令。
Shell > setfacl <option> <FILE_NAME>
选项 | 描述 |
---|---|
-m | 修改文件(s)的当前 ACL(s) |
-x | 从文件(s)的 ACL(s) 中删除条目 |
-b | 删除所有扩展 ACL 条目 |
-d | 操作适用于默认 ACL |
-k | 删除默认 ACL |
-R | 递归进入子目录 |
使用文章开头提到的老师的例子来说明 ACL 的用法。
# The teacher is the root user
Shell > groupadd class1
Shell > mkdir /project
Shell > chown root:class1 /project
Shell > chmod 770 /project
Shell > ls -ld /project/
drwxrwx--- 2 root class1 4096 Jan 12 12:58 /project/
# Put the students in the class into the class1 group
Shell > useradd frank
Shell > passwd frank
Shell > useradd aron
Shell > passwd aron
Shell > gpasswd -a frank class1
Shell > gpasswd -a aron class1
# A student from another school came to listen to the teacher
Shell > useradd tom
Shell > passwd tom
# If it is a group, "u" here should be replaced by "g"
Shell > setfacle -m u:tom:rx /project
# "+" sign is added in the output message
Shell > ls -ld /project/
drwxrwx---+ 2 root class1 4096 Jan 12 12:58 /project/
Shell > getfacl -p /project/
# file: /project/
# owner: root
# group: class1
user::rwx
user:tom:r-x
group::rwx
mask::rwx
other::---
ACL 的最大有效权限¶
使用 getfacl
命令时,输出消息中的 "mask:: rwx" 意味着什么?**掩码** 用于指定最大有效权限。授予用户的权限不是实际权限,实际权限只能通过使用用户权限和掩码权限的“逻辑与”来获得。
信息
“逻辑与”的意思是:如果所有条件都为真,则结果为真;如果有一个条件为假,则结果为假。
用户设置的权限 | 掩码权限 | 结果 |
---|---|---|
r | r | r |
r | - | - |
- | r | - |
- | - | - |
信息
因为默认掩码为 rwx,所以对于任何用户的 ACL 权限,结果都是他们自己的权限。
您也可以调整掩码权限
Shell > setfacl -m u:tom:rwx /project
Shell > setfacl -m m:rx /project
Shell > getfacl -p /project/
# file: project/
# owner: root
# group: class1
user::rwx
user:tom:rwx #effective:r-x
group::rwx #effective:r-x
mask::r-x
other::---
删除 ACL 权限¶
# Delete the ACL permissions of user/group in the specified directory
Shell > setfacl -x u:USER_NAME FILE_NAME
Shell > setfacl -x g:GROUP_NAME FILE_NAME
# Removes all ACL permissions for the specified directory
Shell > setfacl -b FILE_NAME
ACL 权限的默认值和递归¶
什么是 ACL 权限的递归?对于 ACL 权限,这意味着当父目录设置 ACL 权限时,所有子目录和子文件将具有相同的 ACL 权限。
信息
递归适用于目录中已存在的文件/目录。
看下面的例子
Shell > setfacl -m m:rwx /project
Shell > setfacl -m u:tom:rx /project
Shell > cd /project
Shell > touch file1 file2
# Because there is no recursion, the file here does not have ACL permission.
Shell > ls -l
-rw-r--r-- 1 root root 0 Jan 12 14:35 file1
-rw-r--r-- 1 root root 0 Jan 12 14:35 file2
Shell > setfacl -m u:tom:rx -R /project
Shell > ls -l /project
-rw-r-xr--+ 1 root root 0 Jan 12 14:35 file1
-rw-r-xr--+ 1 root root 0 Jan 12 14:35 file2
现在有一个问题:如果我在这个目录中创建一个新文件,它是否具有 ACL 权限?答案是否定的,因为新创建的文件是在执行 setfacl-m u:tom:rx -R /project
命令之后创建的。
Shell > touch /project/file3
Shell > ls -l /project/file3
-rw-r--r-- 1 root root 0 Jan 12 14:52 /project/file3
如果您希望新创建的目录/文件也具有 ACL 权限,则需要使用默认 ACL 权限。
Shell > setfacl -m d:u:tom:rx /project
Shell > cd /project && touch file4 && ls -l
-rw-r-xr--+ 1 root root 0 Jan 12 14:35 file1
-rw-r-xr--+ 1 root root 0 Jan 12 14:35 file2
-rw-r--r-- 1 root root 0 Jan 12 14:52 file3
-rw-rw----+ 1 root root 0 Jan 12 14:59 file4
Shell > getfacl -p /project
# file: /project
# owner: root
# group: class1
user::rwx
user:tom:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:tom:r-x
default:group::rwx
default:mask::rwx
default:other::---
信息
使用 ACL 权限的默认值和递归要求命令的操作对象是一个目录!如果操作对象是一个文件,则会输出错误提示。
SetUID¶
"SetUID" 的作用
- 只有可执行二进制文件才能设置 SUID 权限。
- 命令的执行者应具有对该程序的 x 权限。
- 命令的执行者在执行程序时获得程序文件所有者的身份。
- 身份更改仅在执行期间有效,并且一旦二进制程序完成,执行者的身份将恢复为原始身份。
为什么 GNU/Linux 需要这种奇怪的权限?以最常见的 passwd
命令为例
可以看到,普通用户只有 r 和 x,但所有者的 x 变成了 s,证明 passwd
命令具有 SUID 权限。
众所周知,普通用户 (uid >= 1000) 可以更改自己的密码。实际密码存储在 **/etc/shadow** 文件中,但 shadow 文件的权限是 000,普通用户没有任何权限。
Shell > ls -l /etc/shadow
---------- 1 root root 874 Jan 12 13:42 /etc/shadow
由于普通用户可以更改密码,因此他们必须将密码写入 **/etc/shadow** 文件。当普通用户执行 passwd
命令时,它将临时更改为该文件的所有者 -- **root**。对于 **shadow** 文件,**root** 不会受到权限的限制。这就是为什么 passwd
命令需要 SUID 权限。
如前所述,基本权限可以用数字表示,例如 755、644 等。SUID 由 **4** 表示。对于可执行二进制文件,您可以像这样设置权限 -- **4755**。
# Set SUID permissions
Shell > chmod 4755 FILE_NAME
# or
Shell > chmod u+s FILE_NAME
# Remove SUID permission
Shell > chmod 755 FILE_NAME
# or
Shell > chmod u-s FILE_NAME
警告
当可执行二进制文件/程序的所有者没有 **x** 时,使用大写 **S** 意味着该文件不能使用 SUID 权限。
# Suppose this is an executable binary file
Shell > vim suid.sh
#!/bin/bash
cd /etc && ls
Shell > chmod 4644 suid.sh
警告
由于 SUID 可以临时将普通用户更改为 root,因此在维护服务器时需要特别小心具有此权限的文件。您可以使用以下命令查找具有 SUID 权限的文件
Shell > find / -perm -4000 -a -type f -exec ls -l {} \;
SetGID¶
"SetGID" 的作用
- 只有可执行二进制文件才能设置 SGID 权限。
- 命令的执行者应具有对该程序的 x 权限。
- 命令的执行者在执行程序时获得程序文件所有者组的身份。
- 身份更改仅在执行期间有效,并且一旦二进制程序完成,执行者的身份将恢复为原始身份。
以 locate
命令为例
Shell > rpm -ql mlocate
/usr/bin/locate
...
/var/lib/mlocate/mlocate.db
Shell > ls -l /var/lib/mlocate/mlocate.db
-rw-r----- 1 root slocate 4151779 1月 14 11:43 /var/lib/mlocate/mlocate.db
Shell > ll /usr/bin/locate
-rwx--s--x. 1 root slocate 42248 4月 12 2021 /usr/bin/locate
locate
命令使用 **mlocate.db** 数据库文件快速搜索文件。
因为 locate
命令具有 SGID 权限,所以当执行者(普通用户)执行 locate
命令时,所有者组将切换到 **slocate**。slocate
对 **/var/lib/mlocate/mlocate.db** 文件具有 r 权限。
SGID 由数字 **2** 表示,因此 locate
命令的权限为 2711。
# Set SGID permissions
Shell > chmod 2711 FILE_NAME
# or
Shell > chmod g+s FILE_NAME
# Remove SGID permission
Shell > chmod 711 FILE_NAME
# or
Shell > chmod g-s FILE_NAME
警告
当可执行二进制文件/程序的所有者组没有 **x** 时,使用大写 **S** 表示该文件的 SGID 权限不能正确使用。
# Suppose this is an executable binary file
Shell > touch sgid
Shell > chmod 2741 sgid
Shell > ls -l sgid
-rwxr-S--x 1 root root 0 Jan 14 12:11 sgid
SGID 不仅可以用于可执行二进制文件/程序,还可以用于目录,但很少使用。
- 普通用户必须对该目录具有 rwx 权限。
- 对于普通用户在该目录中创建的文件,默认所有者组是该目录的所有者组。
例如
Shell > mkdir /SGID_dir
Shell > chmod 2777 /SGID_dir
Shell > ls -ld /SGID_dir
drwxrwsrwx 2 root root 4096 Jan 14 12:17 SGID_dir
Shell > su - tom
Shell(tom) > cd /SGID_dir && touch tom_file && ls -l
-rw-rw-r-- 1 tom root 0 Jan 14 12:26 tom_file
警告
由于 SGID 可以临时将普通用户的所有者组更改为 root,因此在维护服务器时需要特别注意具有此权限的文件。您可以通过以下命令查找具有 SGID 权限的文件
Shell > find / -perm -2000 -a -type f -exec ls -l {} \;
粘滞位¶
"粘滞位" 的作用
- 仅对目录有效。
- 普通用户对该目录具有 w 和 x 权限。
- 如果没有粘滞位,具有 w 权限的普通用户可以删除该目录中的所有文件(包括其他用户创建的文件)。一旦目录被赋予 SBIT 权限,只有 root 用户才能删除所有文件。即使普通用户具有 w 权限,他们也只能删除自己创建的文件(其他用户创建的文件不能删除)。
SBIT 由数字 **1** 表示。
文件或目录可以有 **7755** 权限吗?不,它们针对不同的对象。SUID 针对可执行二进制文件;SGID 用于可执行二进制文件和目录;SBIT 仅针对目录。也就是说,您需要根据不同的对象设置这些特殊权限。
目录 **/tmp** 具有 SBIT 权限。下面是一个例子
# The permissions of the /tmp directory are 1777
Shell > ls -ld /tmp
drwxrwxrwt. 8 root root 4096 Jan 14 12:50 /tmp
Shell > su - tom
Shell > cd /tmp && touch tom_file1
Shell > exit
Shell > su - jack
Shell(jack) > cd /tmp && rm -rf tom_file1
rm: cannot remove 'tom_file1': Operation not permitted
Shell(jack) > exit
# The file has been deleted
Shell > su - tom
Shell(tom) > rm -rf /tmp/tom_file1
信息
root (uid=0) 用户不受 SUID、SGID 和 SBIT 权限的限制。
chattr¶
chattr 权限的功能:它用于保护系统中的重要文件或目录,防止它们因误操作而被删除。
chattr
命令的使用 -- chattr [ -RVf ] [ -v version ] [ -p project ] [ mode ] files...
符号模式的格式为 +-=[aAcCdDeFijPsStTu]。
- "+" 表示增加权限;
- "-" 表示减少权限;
- "=" 表示等于一个权限。
最常用的权限(也称为属性)是 **a** 和 **i**。
属性 i 的描述¶
删除 | 自由修改 | 追加文件内容 | 查看 | 创建文件 | |
---|---|---|---|---|---|
文件 | × | × | × | √ | - |
目录 | x (目录和目录下的文件) | √ (目录中的文件) | √ (目录中的文件) | √ (目录中的文件) | x |
文件示例
Shell > touch /tmp/filei
Shell > vim /tmp/filei
123
Shell > chattr +i /tmp/filei
Shell > lsattr -a /tmp/filei
----i---------e----- /tmp/filei
Shell > rm -rf /tmp/filei
rm: cannot remove '/tmp/filei': Operation not permitted
# Cannot be modified freely
Shell > vim /tmp/file1
Shell > echo "adcd" >> /tmp/filei
-bash: /tmp/filei: Operation not permitted
Shell > cat /tmp/filei
123
目录示例
Shell > mkdir /tmp/diri
Shell > cd /tmp/diri && echo "qwer" > f1
Shell > chattr +i /tmp/diri
Shell > lsattr -ad /tmp/diri
----i---------e----- /tmp/diri
Shell > rm -rf /tmp/diri
rm: cannot remove '/tmp/diri/f1': Operation not permitted
# Allow modification
Shell > vim /tmp/diri/f1
qwer-tom
Shell > echo "jim" >> /tmp/diri/f1
Shell > cat /tmp/diri/f1
qwer-tom
jim
Shell > touch /tmp/diri/file2
touch: settng time of '/tmp/diri/file2': No such file or directory
从上面的例子中删除 i 属性
Shell > chattr -i /tmp/filei /tmp/diri
属性 a 的描述¶
删除 | 自由修改 | 追加文件内容 | 查看 | 创建文件 | |
---|---|---|---|---|---|
文件 | × | × | √ | √ | - |
目录 | x (目录和目录下的文件) | x (目录中的文件) | √ (目录中的文件) | √ (目录中的文件) | √ |
文件示例
Shell > touch /etc/tmpfile1
Shell > echo "zxcv" > /etc/tmpfile1
Shell > chattr +a /etc/tmpfile1
Shell > lsattr -a /etc/tmpfile1
-----a--------e----- /etc/tmpfile1
Shell > rm -rf /etc/tmpfile1
rm: cannot remove '/etc/tmpfile1': Operation not permitted
# Cannot be modified freely
Shell > vim /etc/tmpfile1
Shell > echo "new line" >> /etc/tmpfile1
Shell > cat /etc/tmpfile1
zxcv
new line
目录示例
Shell > mkdir /etc/dira
Shell > cd /etc/dira && echo "asdf" > afile
Shell > chattr +a /etc/dira
Shell > lsattr -ad /etc/dira
-----a--------e----- /etc/dira/
Shell > rm -rf /etc/dira
rm: cannot remove '/etc/dira/afile': Operation not permitted
# Free modification is not allowed
Shell > vim /etc/dira/afile
asdf
Shell > echo "new line" >> /etc/dira/afile
Shell > cat /etc/dira/afile
asdf
new line
# Allow creation of new files
Shell > touch /etc/dira/newfile
从上面的例子中删除 a 属性
Shell > chattr -a /etc/tmpfile1 /etc/dira/
问题
当我为文件设置 ai 属性时会发生什么?除了查看之外,您无法对文件执行任何操作。
目录呢?允许的操作包括:自由修改、追加文件内容和查看。不允许的操作包括:删除和创建文件。
sudo¶
"sudo" 的作用
- 通过 root 用户,将只能由 root 用户 (uid=0) 执行的命令分配给普通用户执行。
- "sudo" 的操作对象是系统命令。
我们知道,在 GNU/Linux 目录中,只有管理员 root 用户有权限使用 ** /sbin/ ** 和 ** /usr/sbin/ ** 下的命令。一般来说,公司会有一支团队来维护一组服务器。这组服务器可以指一个地理位置的单一机房,也可以指多个地理位置的机房。团队负责人使用 root 用户的权限,而其他团队成员可能只有普通用户的权限。由于负责人工作量很大,没有时间维护服务器的日常工作,大部分工作需要由普通用户来维护。然而,普通用户在使用命令方面有很多限制,此时就需要使用 sudo 权限。
要授予普通用户权限, **必须使用 root 用户 (uid=0) ** 。
可以使用 visudo
命令来授权普通用户,实际上你修改的是 ** /etc/sudoers ** 文件。
Shell > visudo
...
88 Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
89
90 ## Next comes the main part: which users can run what software on
91 ## which machines (the sudoers file can be shared between multiple
92 ## systems).
93 ## Syntax:
94 ##
95 ## user MACHINE=COMMANDS
96 ##
97 ## The COMMANDS section may have other options added to it.
98 ##
99 ## Allow root to run any commands anywhere
100 root ALL=(ALL) ALL
↓ ↓ ↓ ↓
1 2 3 4
...
部分 | 描述 |
---|---|
1 | 用户名或所有者组名称。指授予哪些用户/组权限。如果是所有者组,需要写 “%”,例如 ** %root ** 。 |
2 | 允许执行命令的机器。可以是单个 IP 地址,网络段,或 ALL 。 |
3 | 指示可以转换为哪些身份。 |
4 | 授权的命令,需要用绝对路径表示。 |
例如
Shell > visudo
...
101 tom ALL=/sbin/shutdown -r now
...
# You can use the "-c" option to check for errors in /etc/sudoers writing.
Shell > visudo -c
Shell > su - tom
# View the available sudo commands.
Shell(tom) > sudo -l
# To use the available sudo command, ordinary users need to add sudo before the command.
Shell(tom) > sudo /sbin/shutdown -r now
如果您的授权命令是 /sbin/shutdown
,则表示授权用户可以使用该命令的任何选项。
警告
由于 sudo 是一个 “越权” 操作,在处理 ** /etc/sudoers ** 文件时需要格外小心!
作者: tianci li
贡献者: Serge, Ganna Zhyrnova