在linux上使用python从smb共享获取文件的所有者

kak*_*dol 1 linux smb cifs cacls python-3.x

我需要找出我正在编写的脚本谁是 smb 共享中文件的真正所有者(mount -t cifs当然使用我的服务器安装并net use通过 Windows 机器使用)。

事实证明,在 Linux 服务器上使用 python 查找这些信息确实是一个挑战。

我尝试使用很多 smb 库(例如 smbprotocol、smbclient 等),但没有任何效果。
我发现很少有针对 Windows 的解决方案,它们都使用 pywin32 或其他 Windows 特定的包。
我还设法使用 bash 来做到这一点smbcalcs,但不能干净地做到这一点,但使用subprocess.popen('smbcacls')..

关于如何解决它有什么想法吗?

kak*_*dol 7

令人难以置信的是,这不是一项微不足道的任务,不幸的是,答案并不像我希望的那样简单。

如果将来有人遇到同样的问题,我会发布这个答案,但希望有人能早点发布更好的解决方案

为了找到所有者,我使用了这个库及其示例

from smb.SMBConnection import SMBConnection

conn = SMBConnection(username='<username>', password='<password>', domain='<domain>', my_name='<some pc name>', remote_name='<server name>')
conn.connect('<server name>')

sec_att = conn.getSecurity('<share name>', r'\some\file\path')
owner_sid = sec_att.owner
Run Code Online (Sandbox Code Playgroud)

问题是这个pysmb包只会给你所有者的 SID 而不是他的名字。
为了获取他的名字,您需要像这个答案一样进行 ldap 查询(重新发布代码):

from ldap3 import Server, Connection, ALL
from ldap3.utils.conv import escape_bytes

s = Server('my_server', get_info=ALL)
c = Connection(s, 'my_user', 'my_password')
c.bind()

binary_sid = b'....'  # your sid must be in binary format

c.search('my_base', '(objectsid=' + escape_bytes(binary_sid) + ')', attributes=['objectsid', 'samaccountname'])
print(c.entries)
Run Code Online (Sandbox Code Playgroud)

当然,没有什么是容易的,我花了几个小时才找到一种在 python 中将字符串 SID 转换为二进制 SID 的方法,最终解决了这个问题

# posting the needed functions and omitting the class part
def byte(strsid):
    '''
    Convert a SID into bytes
        strdsid - SID to convert into bytes
    '''
    sid = str.split(strsid, '-')
    ret = bytearray()
    sid.remove('S')
    for i in range(len(sid)):
        sid[i] = int(sid[i])
    sid.insert(1, len(sid)-2)
    ret += longToByte(sid[0], size=1)
    ret += longToByte(sid[1], size=1)
    ret += longToByte(sid[2], False, 6)
    for i in range(3, len(sid)):
        ret += cls.longToByte(sid[i])
    return ret

def byteToLong(byte, little_endian=True):
    '''
    Convert bytes into a Python integer
        byte - bytes to convert
        little_endian - True (default) or False for little or big endian
    '''
    if len(byte) > 8:
        raise Exception('Bytes too long. Needs to be <= 8 or 64bit')
    else:
        if little_endian:
            a = byte.ljust(8, b'\x00')
            return struct.unpack('<q', a)[0]
        else:
            a = byte.rjust(8, b'\x00')
            return struct.unpack('>q', a)[0]  
Run Code Online (Sandbox Code Playgroud)

...最后您得到了完整的解决方案!享受 :(