在Linux系统上,与使用文件功能添加setuid位相比,可以更有选择性地授予root权限。有关详细信息,请参阅capabilities(7)
。这些是文件的属性,可以使用getcap
程序读取。如何在Python中检索这些属性?
即使使用例如getcap
程序运行subprocess
用于回答这样的问题是可能的,在检索很多功能时是不可取的。
应该可以使用ctypes
设计解决方案。是否有替代方法或甚至图书馆促进这项任务?
答案 0 :(得分:6)
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
个字符串。使用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
要费力。
答案 1 :(得分:0)
我尝试了RicardoCárdenes的答案中的代码,但它对我不起作用,因为ctypes
调用的某些细节不正确。此问题导致截断的路径字符串传递到getxattr(...)
内的libcap
,从而返回错误项目(/
目录或其他第一个路径字符的错误功能列表,而不是实际的路径。)
记住并说明Python 3.X中str
和bytes
之间的区别非常重要。此代码适用于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