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

yquaqz18  于 5个月前  发布在  Linux
关注(0)|答案(3)|浏览(65)

在Linux系统上,root权限可以比使用文件功能添加setuid位更有选择性地授予。有关详细信息,请参阅capabilities(7)。这些是文件的属性,可以使用getcap程序读取。如何在Python中检索这些属性?
即使使用例如subprocess来运行getcap程序来回答这样的问题是可能的,但是在检索非常多的能力时是不期望的。
应该可以使用ctypes设计一个解决方案。有没有替代这种方法的方法,甚至有没有帮助完成这项任务的库?

xriantvc

xriantvc1#

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
现在,我们得到了原始结果,这意味着这两个只在检索文本属性时最有用。但是...我们可以使用与getcap相同的方法,通过libcap本身[警告,这将仅在Python 2上按原样工作,如最初编写的那样-阅读结尾的注解以了解详细信息]:

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进行释放

关于“binary gibberish”的提示:

>>> 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要费力得多。
PS2:我注意到另一个回答提到我在ctype解决方案上的调用有问题。这是因为我 * 可能 * 在2014年使用Python 2.x编写的(因为Python 3提供了os.getxattr)。
这里的关键是要提醒,在Python 2.x中没有bytes对象,strunicode是独立的实体。Python 3.x合并了这两个对象,因此str现在基本上是unicode,这可能会扰乱C接口。
因此,如果使用Python 3(可能是目前的情况),请确保在将字符串传递给libcap之前将其转换为bytes(例如,foo_bar.encode('utf-8')),并对结果进行反向操作。

sc4hvdpw

sc4hvdpw2#

我尝试了Ricardo Cárdenes的答案中的代码,但它对我来说不能正常工作,因为ctypes调用的一些细节不正确。这个问题导致一个截断的路径字符串被传递到libcap内部的getxattr(...),从而为错误的项目返回了错误的功能列表(/目录,或其他第一个路径字符,而不是实际的路径)。
记住并解释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

vh0rcniy

vh0rcniy3#

getcap.py

import ctypes, sys, glob

libcap = ctypes.cdll.LoadLibrary(glob.glob("/lib/libcap*")[0])
cap_t = libcap.cap_get_file(sys.argv[1])
libcap.cap_to_text.restype = ctypes.c_char_p
print libcap.cap_to_text(cap_t, None)

字符串
setcap.py all capabilities =ep)

import ctypes, sys, glob

libcap = ctypes.cdll.LoadLibrary(glob.glob("/lib/libcap*")[0])

libcap.cap_from_text.argtypes = [ctypes.c_char_p]
libcap.cap_from_text.restype = ctypes.c_void_p
libcap.cap_set_file.argtypes = [ctypes.c_char_p,ctypes.c_void_p]

cap = '=ep'
path = sys.argv[1]
print(path)
cap_t = libcap.cap_from_text(cap)
status = libcap.cap_set_file(path,cap_t)

if(status == 0):
    print (cap + " was successfully added to " + path)


备注:

  • 我搜索库,因为在某些系统上库名称会更改。
  • Setcap设置所有功能。您可以更改代码或添加一个argv来添加任何功能。

相关问题