ACL 访问控制列表
ACL 全称为 Access Control List 。因为传统的 Linux 权限只能针对拥有者和拥有者的有效群组及非此群组的其他人设定权限而已,如果你想要不同的人或者群组设置不同的权限,则无法做到。ACL 就是为了解决这种问题。
在现在的 Linux 的文件系统中基本上都支持了 ACL,我们可以通过以下命令查看:
1 2 3 4 |
$ dumpe2fs -h /dev/vda1 | grep -i acl dumpe2fs 1.42.9 (28-Dec-2013) Default mount options: user_xattr acl |
首先我们需要知道两个指令:
getfacl
:取得某个文件/目录的 ACL 设定。setfacl
:设定某个目录/文件的 ACL 。
首先来说 setfacl(set file acl):
1 2 3 4 5 6 7 8 9 |
$ setfacl [-bkRd] [{-m|-x} acl 参数] 目标文件 选项与参数: -m :设定后续的 acl 参数给文件使用,不可与 -x 合用; -x :删除后续的 acl 参数,不可与 -m 合用; -b :移除所有的 ACL 设定参数; -k :移除预设的 ACL 参数,关于所谓的『预设』参数于后续范例中介绍; -R :递归设定 acl ,亦即包括次目录都会被设定起来; -d :设定预设 acl 参数的意思!只对目录有效,在该目录新建的数据会引用此默认值 |
其中如果设定某个用户的权限,应用 u:[使用者账号列表]:[rwx]
。同理如果设置某个群组,应用 g:[群组列表]:[rwx]
。注意:如果列表为空,则代表为拥有者和群组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ setfacl -m u:bonky:rwx test1 $ getfacl test1 # file: test1 # owner: root # group: root user::rw- user:bonky:rwx group::r-- mask::rwx other::r-- $ ll test1 -rw-rwxr--+ 1 root root 0 1月 19 21:29 test1 |
可以发现和一般的不同,用户 bonky 的权限设置为了 rwx,然后就是使用 ll 指令的时候发现权限那一栏的最后多了个 + 号。
你也可能注意到了,在 getfacl 有这么一行:mask::rwx
,作用是规定了最高的有效的权限。如果 mask::r--
那么所有用户和群组最大只能拥有读的权限,即便我设置权限为 rwx。如果你想要修改 mask 设定,只需要使用 m:[rwx]
来设定。
对于目录我们可以通过 d:[u|g]:使用者或列表:[rwx]
对用户和群组设置默认权限,在目录下创建的所有文件都对用户有相应权限。
切换到管理员
用户切换 su
1 2 3 4 5 |
$ su # 直接切换到 root $ su bonky # 切换到 bonky $ su -c "id" bonky # 以 bonky 的身份执行一条指令(未指明用户则为 root) uid=1000(bonky) gid=1001(bonky) 组=1001(bonky),1000(user) |
以用户运行 sudo
1 2 3 4 5 |
$ sudo [-b] [-u 新使用者账号] 选项与参数: -b :将后续的指令放到背景中让系统自行执行,而不与目前的 shell 产生影响 -u :后面可以接欲切换的使用者,若无此项则代表切换身份为 root 。 |
但是注意,预设情况下只有 root 可以用。这和 sudo 的执行原理有关:
- 当用户执行 sudo 时,系统于
/etc/sudoers
文件中搜寻该使用者是否有执行 sudo 的权限(默认只有 root) - 若使用者具有可执行 sudo 的权限后,便让使用者『输入用户自己的密码』来确认
- 若密码输入成功,便开始进行 sudo 后续接的指令 (但 root 执行 sudo 时,不需要输入密码)
- 若欲切换的身份与执行者身份相同,那也不需要输入密码。
一般来说,修改 /etc/sudoers
文件不是直接修改他,而是通过 visudo 指令,修改完成后,visudo 指令可以帮你检查语法,避免写错了带来不必要的麻烦。如果你想要加入某个用户到 sudoer 的话,首先使用 visudo 指令,然后找到这一行:
1 2 3 |
## Allow root to run any commands anywhere root ALL=(ALL) ALL |
然后按照下面规则进行修改即可:
1 2 3 |
使用者账号 登入者的来源主机名=(可切换的身份) 可下达的指令 root ALL=(ALL) ALL |
- 登入者的来源主机名:代表当这个账号由哪部主机联机到本 Linux 主机,意思是这个账号可能是由哪一部网络主机联机过来的, 这个设定值可以指定客户端计算机(信任的来源的意思)。默认值 root 可来自任何一部主机。
- 可切换的身份:代表这个账号可以切换成什么身份来下达后续的指令,默认 root 可以切换成任何人。
- 可下达的指令:可用该身份下达什么指令。这个指令请务必使用绝对路径撰写。 预设 root 可以切换任何身份且进行任何指令之意。
当然,我们也可以设置为群组:
1 2 3 |
使用者账号 登入者的来源主机名=(可切换的身份) 可下达的指令 %wheel ALL=(ALL) ALL |
其实 macOS 就是这样子设置所有的管理员可以执行 sudo 命令的,macOS 默认只有 root 和 admin 群组的可以执行 sudo 命令。
PAM 模块
什么是 PAM
PAM(Pluggable Authentication Modules)是一个 API,他提供了一连串的验证机制,只要使用者将验证阶段的需求告知 PAM 后, PAM 就能够回报使用者验证的结果成功或失败。
设计的初衷是将不同的底层认证机制集中到一个高层次的API中,从而省去开发人员自己去设计和实现各种繁杂的认证机制的麻烦。如果没有 PAM ,认证功能只能写在各个应用程序中,一旦要修改某个认证方法,开发人员可能不得不重写程序,然后重新编译程序并安装;有了 PAM ,认证的工作都交给 PAM ,程序主体便可以不再关注认证问题了。
下面这个是一个登录所执行的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#%PAM-1.0 auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so auth substack system-auth auth include postlogin account required pam_nologin.so account include system-auth password include system-auth # pam_selinux.so close should be the first session rule session required pam_selinux.so close session required pam_loginuid.so session optional pam_console.so # pam_selinux.so open should only be followed by sessions to be executed in the user context session required pam_selinux.so open session required pam_namespace.so session optional pam_keyinit.so force revoke session include system-auth session include postlogin -session optional pam_ck_connector.so |
每一行代表一条规则。但也可以用 \
来放在行末,来连接该行和下一行。
例子的最后一行开头有一个短横线 -
,意思是如果找不到这个模块,导致无法被加载时,这一事件不会被记录在日志中。这个功能适用于那些认证时非必需的、安装时可能没被安装进系统的模块。
PAM 模块一般保存在 /lib/security
或 /lib64/security
中(取决于操作系统位数)。
PAM 验证的详细日志信息可以查看文件 /var/log/secure
。
PAM 模块设定
执行程序 passwd 后,流程如下:
- 用户开始执行
/usr/bin/passwd
这支程序,并输入密码; - passwd 呼叫 PAM 模块进行验证;
- PAM 模块会到
/etc/pam.d/
找寻与程序 (passwd) 同名的配置文件; - 依据
/etc/pam.d/passwd
内的设定,引用相关的 PAM 模块逐步进行验证分析; - 将验证结果 (成功、失败以及其他讯息) 回传给 passwd 这支程序;
- passwd 这支程序会根据 PAM 回传的结果决定下一个动作 (重新输入新密码或者通过验证!)
然后,我们来看看 passwd 的 pam 设定文件:
1 2 3 4 5 6 7 8 |
➜ ~ 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 |
第一列是验证的模块(类别):
account
:主要判断用户是否可以使用某个服务,但不负责身份认证。对用户的各项属性进行检查。比如是否允许登录,是否达到最大用户数。auth
:实现身份认证以及权限授予,比如赋给用户某个组的组员身份。session
:实现用户登录前的,及用户退出后所要进行的操作。比如登录连接信息,用户数据的打开与关闭,挂载文件系统等。password
:实现设置密码相关的一些东西。比如设置,修改密码,以及检测密码是否满足安全性。
第二列指明了控制模式。控制模式用来标记处理和判断各个模块的返回值。控制模式关键字分为六种:
required
:此验证若成功则带有 success (成功) 的标志,若失败则带有 failure 的标志,但不论成功或失败都会继续后续的验证流程。由于后续的验证流程可以继续进行,因此相当有利于记录日志,这也是 PAM 最常使用 required 的原因。requisite
: 如果返回失败,则立刻向应用程序返回失败。sufficient
: 若验证成功则立刻回传成功给原程序,并终止后续的验证流程;若验证失败则带有 failure 标志并继续。optional
: 一般是用于显示信息(比如密码错了提示再次输入)include
: 调用其它程序的 PAM 配置。substack
:和include类似。不同之处在于,如果某个流程栈 include 了一个带 requisite 的栈,这个 requisite 失败将直接导致认证失败,同时退出栈;而某个流程栈 substack 了同样的栈时,requisite 的失败只会导致这个子栈返回失败信号,母栈并不会在此退出。
控制模式除了关键字写法,还有一种写法是类似于这样子的:
1 2 |
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so |
其中等号左边是各个认证模块执行之后的返回值,有 success
、user_unknown
、new_authtok_reqd
、default
等等,default
代表着所有未说明的返回值。后面那个 actionN 决定哪一个验证规则能作为最终的结果。
ignore
:在一个栈中有多个认证条目的情况下,如果标记 ignore 的返回值被命中,那么这条返回值不会对最终的认证结果产生影响。bad
:标记 bad 的返回值被命中时,最终的认证结果注定会失败。此外,如果这条 bad 的返回值是整个栈的第一个失败项,那么整个栈的返回值一定是这个返回值,后面的认证无论结果怎样都改变不了现状了。die
:标记 die 的返回值被命中时,马上退出栈并宣告失败。整个返回值为这个 die 的返回值。ok
:在一个栈的运行过程中,如果 ok 前面没有返回值,或者前面的返回值为 PAM_SUCCESS,那么这个标记了 ok 的返回值将覆盖前面的返回值。但如果前面执行过的验证中有最终将导致失败的返回值,那 ok 标记的值将不会起作用。done
:在前面没有 bad 值被命中的情况下,done 值被命中之后将马上被返回,并退出整个栈。N(一个自然数)
:功效和 ok 类似,并且会跳过接下来的 N 个验证步骤。如果 N = 0 则和 ok 完全相同。reset
:清空之前生效的返回值,并且从下面的验证起重新开始。
其实上面的前四条关键词可以这么表示:
required
:[success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite
:[success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient
:[success=done new_authtok_reqd=done default=ignore]
optional
:[success=ok new_authtok_reqd=ok default=ignore]
实战和参考资料
可以看看教程:
- Linux系统安全之pam后门安装使用详解
- Linux-PAM 小实验,这个教程还讲了利用 PAM 和 Google Authenticator 给 CentOS 添加一次性密码。
由于 PAM 东西实在太多,然后一下子也用不上,记录下一些文档,方便以后查询:
- 这里是使用 PAM 的 document:The Linux-PAM Application Developers’ Guide
- 这里是写 PAM 模块的教程:The Linux-PAM Module Writers’ Guide
用户信息
查询使用者:w, who, last, lastlog
w 和 who 作用差不多,只不过 who 显示的信息比较详细。
1 2 3 4 5 6 7 8 9 10 11 12 |
➜ ~ w 22:51:43 up 33 days, 6:56, 3 users, load average: 5.10, 5.74, 6.64 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT amax pts/2 172.16.14.80 22:51 5.00s 0.24s 0.01s w stu26 pts/8 172.16.14.130 10Jan20 8days 0.08s 0.08s -bash amax pts/9 172.16.14.80 22:51 5.00s 0.21s 0.21s -zsh ➜ ~ who amax pts/2 Jan 20 22:51 (172.16.14.80) stu26 pts/8 Jan 10 11:43 (172.16.14.130) amax pts/9 Jan 20 22:51 (172.16.14.80) |
last 会显示所有的登录信息:
1 2 3 4 5 6 |
➜ ~ last | grep amax amax pts/9 172.16.14.80 Mon Jan 20 22:51 still logged in amax pts/2 172.16.14.80 Mon Jan 20 22:51 still logged in amax pts/9 172.16.14.80 Mon Jan 20 11:36 - 11:57 (00:20) ...... |
lastlog 会显示最近一次的 log 信息:
1 2 3 |
➜ ~ lastlog | grep amax amax pts/9 172.16.14.80 Mon Jan 20 22:59:46 +0800 2020 |
用户交流:write, mesg, wall
write 可以传消息给另外一个用户:
1 2 |
write 使用者账号 [用户所在终端接口] |
使用效果是这样子的,我把左边的传给另外一个终端:
但注意,传消息的时候会打断另外一个人本来的工作(程序不会终止,但你无法输入东西)。如果不想接受别人的信息请使用 mesg n
,这时我们再想写入则会提示:
1 2 3 |
➜ ~ write bonky ttys002 write: bonky has messages disabled on ttys002 |
想要取消的话可以使用 mesg y
。如果你想要给所有人发信息,请使用 wall 指令,当然自己也会收到:
1 2 3 4 5 6 7 |
$ wall "Hello World" $ Broadcast message from root@VM_0_3_centos (pts/0) (Mon Jan 20 23:13:37 2020): Hello World |
注意 Mac 上后面只能接文件:wall [-g group] [file]
。(不过能够指定群组还是很不错的,而 Linux 不能)
用户信箱: mail
上面我们讲的那些都需要对方在线才能进行联络,如果想要非在线的联络的话,请使用 mail。
一般使用方法如下 mail -s "邮件标题" username@localhost
,如果发送给本机的用户则不需要填写 localhost~
然后查看邮件的话直接使用 mail 指令进入交互界面就好了~
1 2 3 4 5 6 |
$ mail Heirloom Mail version 12.5 7/5/10. Type ? for help. "/var/spool/mail/stu02": 1 message 1 new >N 1 amax Mon Jan 20 23:21 18/626 "Fuck you Ass" & |
在 mail 当中的提示字符是 & 符号,然后我们可以再输入 ? 进行查询内部的指令。比较常用的有这些: