它可以通过 libcap 来完成 - 它提供了一个 PAM 模块 pam_cap.so。
然而,这并不是相当那么简单:)
每个流程都有三个能力集:
- Effective(此过程实际具有的上限)
- 允许(此过程可能具有的上限 - Effective 的超集)
- 可继承(此进程可以传递给子进程的上限)
每个文件都有相同的能力集。当一个新的二进制文件被 exec()'d 时,进程的能力会根据以下规则发生变化,其中:
(从http://www.friedhoff.org/posixfilecaps.html简化)
在大多数情况下,pE' 是我们唯一关心的结果。与 libcap 链接的程序可以调用 setcap() 来更改其有效上限(只要他们尝试请求的上限在允许集中),但是绝大多数程序没有明确地触及他们的上限,所以我们必须安排上限在 exec() 后生效。
有一个具体的例子将有助于理解这里...我已经厌倦了必须“su”来运行 openvpn,所以我想授予自己 CAP_NET_ADMIN 功能以允许设置路由等。
查看最后一条规则 (pE' = fE & pP') 很明显,要将 CAP_NET_ADMIN 包含在进程的有效集中,CAP_NET_ADMIN 必须在文件的有效集中。因此,功能系统不允许我们简单地说“将 CAP_NET_ADMIN 授予用户 sqweek” - 程序的功能始终很重要。
仅仅在文件的有效集中是不够的,上限还需要在进程的新允许集中。让我们看看这条规则:pP' = fP | (pI & fI)。所以我们有两种方法可以在pP' 中获取上限,或者将 CAP_NET_ADMIN 添加到文件的 Permitted 集中,或者将其添加到文件的 Inheritable 集中并确保它在进程的 Inheritable 集中。
如果我们将它添加到文件的 Permitted 集中,那么进程的初始功能变得无关紧要 - openvpn 每次运行时都会获得 CAP_NET_ADMIN,无论是谁运行它。这类似于 setuid,但提供了更细粒度的方法。不过,这不是每个用户的粒度,所以让我们看看另一个选项。
注意第一条规则,pI' = pI。进程的 Inheritable 功能不受 exec() 的影响。这意味着,我们只需要一个可识别 libcap 的程序将 CAP_NET_ADMIN 设置为 Inheritable cap,并且从那里产生的每个进程也具有 CAP_NET_ADMIN Inheritable。这是 pam 模块所扮演的角色 - 它在登录期间修改 Inheritable 集,然后为该用户的所有进程继承该集。
总结一下:
- 安装 libcap
- 配置 pam_cap 模块(将
cap_net_admin sqweek 行添加到 /etc/security/capability.conf。如果该文件以前不存在,请添加另一行 none * 以获得合理的默认值。
- 在登录期间启用 PAM 模块(将
auth required pam_cap.so 添加到 /etc/pam.d/login)。 在进行 PAM 更改时,请务必在注销之前在单独的终端中测试您的登录信息,以免将自己锁定!
- 将 CAP_NET_ADMIN 添加到 openvpn 的有效和可继承集 (
setcap cap_net_admin+ie /usr/sbin/openvpn)
-
openvpn调用ip更改路由表等,所以需要同样的处理(setcap cap_net_admin+ie /sbin/ip)
请注意,/etc/pam.d/login 仅管理本地登录 - 您可能想要提供例如。 /etc/pam.d/sshd 类似处理。此外,当您的包管理器安装新版本的目标二进制文件时,您通过 setcap 添加的任何功能都将被吹走,因此您必须重新添加它们。