Получение владельца файла из общего ресурса smb с помощью python в linux

Мне нужно выяснить для сценария, который я пишу, кто является истинным владельцем файла в общем ресурсе smb (конечно, смонтированном с использованием mount -t cifs на моем сервере и с использованием net use через машины Windows).

Оказывается, найти эту информацию с помощью Python на сервере Linux — настоящая проблема.

Я пробовал использовать много-много smb-библиотек (таких как smbprotocol, smbclient и другие), ничего не помогло.
Я нашел несколько решений для Windows, все они используют pywin32 или другой пакет, специфичный для Windows.
И мне тоже удалось это сделать. из bash, используя smbcalcs, но не смог сделать это чисто, но используя subprocess.popen('smbcacls')..

Любая идея о том, как это решить?


person kaki gadol    schedule 26.05.2020    source источник


Ответы (1)


Это была невероятно нетривиальная задача, и, к сожалению, ответ не так прост, как я надеялся.

Я публикую этот ответ, если кто-то столкнется с этой же проблемой в будущем, но надеюсь, что, возможно, кто-то опубликует лучшее решение раньше.

Чтобы найти владельца, я использовал эту библиотеку с примерами:

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

Проблема в том, что пакет 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)

Но, конечно, ничего не будет легко, мне потребовались часы, чтобы найти способ преобразовать строковый SID в двоичный SID в python, и, в конце концов, это решило проблему:

# 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]  

... И, наконец, у вас есть полное решение! наслаждаться :(

person kaki gadol    schedule 01.06.2020
comment
Блин, это немного перетасовка для базовой функциональности... :D - person andreas; 09.11.2020