如何使用Python读取文件功能?

时间:2014-02-04 18:48:07

标签: python linux linux-capabilities

在Linux系统上,与使用文件功能添加setuid位相比,可以更有选择性地授予root权限。有关详细信息,请参阅capabilities(7)。这些是文件的属性,可以使用getcap程序读取。如何在Python中检索这些属性?

即使使用例如getcap程序运行subprocess用于回答这样的问题是可能的,在检索很多功能时是不可取的。

应该可以使用ctypes设计解决方案。是否有替代方法或甚至图书馆促进这项任务?

2 个答案:

答案 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中strbytes之间的区别非常重要。此代码适用于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