在 Linux 系统上,可以比使用文件功能添加 setuid 位更有选择性地授予 root 权限。详情请参阅capabilities(7)
。这些是文件的属性,可以使用getcap
程序读取。如何在 Python 中检索这些属性?
即使getcap
使用例如来运行程序来subprocess
回答这样的问题是可能的,但在检索非常多的能力时它是不可取的。
应该可以使用ctypes
. 是否有这种方法的替代品,甚至有图书馆促进这项任务?
在 Linux 系统上,可以比使用文件功能添加 setuid 位更有选择性地授予 root 权限。详情请参阅capabilities(7)
。这些是文件的属性,可以使用getcap
程序读取。如何在 Python 中检索这些属性?
即使getcap
使用例如来运行程序来subprocess
回答这样的问题是可能的,但在检索非常多的能力时它是不可取的。
应该可以使用ctypes
. 是否有这种方法的替代品,甚至有图书馆促进这项任务?
Python 3.3 带有os.getxattr
. 如果不是,是的......一种方法是使用ctypes
,至少是为了得到原始的东西,或者也许使用pyxattr
对于pyxattr
:
>>> import xattr
>>> xattr.listxattr("/bin/ping")
(u'security.capability',)
>>> xattr.getxattr("/bin/ping", "security.capability")
'\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
对于 Python 3.3 的版本,它本质上是一样的,只是导入os
. 而不是xattr
. ctypes
不过,涉及更多。
现在,我们得到了原始结果,这意味着这两个最有用的只是检索文本属性。但是......我们可以getcap
通过libcap
自身使用相同的方法:
import ctypes
libcap = ctypes.cdll.LoadLibrary("libcap.so")
cap_t = libcap.cap_get_file('/bin/ping')
libcap.cap_to_text.restype = ctypes.c_char_p
libcap.cap_to_text(cap_t, None)
这给了我:
'= cap_net_raw+p'
可能对你更有用。
PS:注意cap_to_text
返回一个malloc
ed 字符串。你的工作是使用它来释放它cap_free
关于“二进制乱码”的提示:
>>> import struct
>>> caps = '\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> struct.unpack("<IIIII", caps)
(33554432, 8192, 0, 0, 0)
其中8192
,唯一有效的位是第 13 位。如果你去linux/capability.h
,你会看到CAP_NET_RAW
定义在13
。
现在,如果你想用所有这些常量编写一个模块,你可以解码信息。但我想说这比使用ctypes
+更费力libcap
。
我尝试了 Ricardo Cárdenes 回答中的代码,但它对我来说不能正常工作,因为ctypes
调用的一些细节不正确。此问题导致将截断的路径字符串传递到getxattr(...)
内部libcap
,从而为错误的项目(/
目录或其他第一个路径字符,而不是实际路径)返回错误的功能列表。
str
记住和解释bytes
Python 3.X之间的区别非常重要。此代码在 Python 3.5/3.6 上正常工作:
#!/usr/bin/env python3
import ctypes
import os
import sys
# load shared library
libcap = ctypes.cdll.LoadLibrary('libcap.so')
class libcap_auto_c_char_p(ctypes.c_char_p):
def __del__(self):
libcap.cap_free(self)
# cap_t cap_get_file(const char *path_p)
libcap.cap_get_file.argtypes = [ctypes.c_char_p]
libcap.cap_get_file.restype = ctypes.c_void_p
# char* cap_to_text(cap_t caps, ssize_t *length_p)
libcap.cap_to_text.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
libcap.cap_to_text.restype = libcap_auto_c_char_p
def cap_get_file(path):
cap_t = libcap.cap_get_file(path.encode('utf-8'))
if cap_t is None:
return ''
else:
return libcap.cap_to_text(cap_t, None).value.decode('utf-8')
print(cap_get_file('/usr/bin/traceroute6.iputils'))
print(cap_get_file('/usr/bin/systemd-detect-virt'))
print(cap_get_file('/usr/bin/mtr'))
print(cap_get_file('/usr/bin/tar'))
print(cap_get_file('/usr/bin/bogus'))
输出将如下所示(任何不存在或没有设置功能的内容都将返回''
:
= cap_net_raw+ep
= cap_dac_override,cap_sys_ptrace+ep
= cap_net_raw+ep