如何在没有 pywin32 的情况下使用 python 确定 Windows 上的文件所有者

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8086412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:26:44  来源:igfitidea点击:

Howto determine file owner on windows using python without pywin32

pythonwindows

提问by circus

I am writing a script which needs to determine the username of the owner of files on windows.

我正在编写一个脚本,需要确定 Windows 上文件所有者的用户名。

While I found a solution using pywin32but I am hesitant to use it, as I do not want to add the module dependency.

虽然我找到了一个使用 pywin32 的解决方案,但我对使用它犹豫不决,因为我不想添加模块依赖项。

The script will be written for python 2.6 and has to run on both 32bit and 64 plattforms.

该脚本将针对 python 2.6 编写,并且必须在 32 位和 64 位平台上运行。

I was wondering if there is a different method, maybe with ctypes, to determine this information

我想知道是否有不同的方法,也许用 ctypes,来确定这些信息

回答by Eryk Sun

The following uses ctypes to call GetNamedSecurityInfo. Originally it followed the code snippetthat's linked in the question, but GetNamedSecurityInfois more useful in general than GetFileSecurity, especially since it's paired with SetNamedSecurityInfoin place of the obsolete function SetFileSecurity.

下面使用 ctypes 来调用GetNamedSecurityInfo. 最初它遵循问题中链接的代码片段,但GetNamedSecurityInfo一般来说比 更有用GetFileSecurity,特别是因为它与SetNamedSecurityInfo过时的 function配对SetFileSecurity

ctypes and classes

ctypes 和类

import ctypes as ctypes
from ctypes import wintypes as wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)

ERROR_INVALID_FUNCTION  = 0x0001
ERROR_FILE_NOT_FOUND    = 0x0002
ERROR_PATH_NOT_FOUND    = 0x0003
ERROR_ACCESS_DENIED     = 0x0005
ERROR_SHARING_VIOLATION = 0x0020

SE_FILE_OBJECT = 1
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION  = 0x00000004
SACL_SECURITY_INFORMATION  = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010

_DEFAULT_SECURITY_INFORMATION = (OWNER_SECURITY_INFORMATION |
    GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION |
    LABEL_SECURITY_INFORMATION)

LPDWORD = ctypes.POINTER(wintypes.DWORD)
SE_OBJECT_TYPE = wintypes.DWORD
SECURITY_INFORMATION = wintypes.DWORD

class SID_NAME_USE(wintypes.DWORD):
    _sid_types = dict(enumerate('''
        User Group Domain Alias WellKnownGroup DeletedAccount
        Invalid Unknown Computer Label'''.split(), 1))

    def __init__(self, value=None):
        if value is not None:
            if value not in self.sid_types:
                raise ValueError('invalid SID type')
            wintypes.DWORD.__init__(value)

    def __str__(self):
        if self.value not in self._sid_types:
            raise ValueError('invalid SID type')
        return self._sid_types[self.value]

    def __repr__(self):
        return 'SID_NAME_USE(%s)' % self.value

PSID_NAME_USE = ctypes.POINTER(SID_NAME_USE)

class PLOCAL(wintypes.LPVOID):
    _needs_free = False
    def __init__(self, value=None, needs_free=False):
        super(PLOCAL, self).__init__(value)
        self._needs_free = needs_free

    def __del__(self):
        if self and self._needs_free:
            kernel32.LocalFree(self)
            self._needs_free = False

PACL = PLOCAL

class PSID(PLOCAL):
    def __init__(self, value=None, needs_free=False):
        super(PSID, self).__init__(value, needs_free)

    def __str__(self):
        if not self:
            raise ValueError('NULL pointer access')
        sid = wintypes.LPWSTR()
        advapi32.ConvertSidToStringSidW(self, ctypes.byref(sid))
        try:
            return sid.value
        finally:
            if sid:
                kernel32.LocalFree(sid)

class PSECURITY_DESCRIPTOR(PLOCAL):
    def __init__(self, value=None, needs_free=False):
        super(PSECURITY_DESCRIPTOR, self).__init__(value, needs_free)
        self.pOwner = PSID()
        self.pGroup = PSID()
        self.pDacl = PACL()
        self.pSacl = PACL()
        # back references to keep this object alive
        self.pOwner._SD = self
        self.pGroup._SD = self
        self.pDacl._SD = self
        self.pSacl._SD = self

    def get_owner(self, system_name=None):
        if not self or not self.pOwner:
            raise ValueError('NULL pointer access')
        return look_up_account_sid(self.pOwner, system_name)

    def get_group(self, system_name=None):
        if not self or not self.pGroup:
            raise ValueError('NULL pointer access')
        return look_up_account_sid(self.pGroup, system_name)

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

# msdn.microsoft.com/en-us/library/aa376399
advapi32.ConvertSidToStringSidW.errcheck = _check_bool
advapi32.ConvertSidToStringSidW.argtypes = (
    PSID, # _In_   Sid
    ctypes.POINTER(wintypes.LPWSTR)) # _Out_ StringSid

# msdn.microsoft.com/en-us/library/aa379166
advapi32.LookupAccountSidW.errcheck = _check_bool
advapi32.LookupAccountSidW.argtypes = (
    wintypes.LPCWSTR, # _In_opt_  lpSystemName
    PSID,             # _In_      lpSid
    wintypes.LPCWSTR, # _Out_opt_ lpName
    LPDWORD,          # _Inout_   cchName
    wintypes.LPCWSTR, # _Out_opt_ lpReferencedDomainName
    LPDWORD,          # _Inout_   cchReferencedDomainName
    PSID_NAME_USE)    # _Out_     peUse

# msdn.microsoft.com/en-us/library/aa446645
advapi32.GetNamedSecurityInfoW.restype = wintypes.DWORD
advapi32.GetNamedSecurityInfoW.argtypes = (
    wintypes.LPWSTR,       # _In_      pObjectName
    SE_OBJECT_TYPE,        # _In_      ObjectType
    SECURITY_INFORMATION,  # _In_      SecurityInfo
    ctypes.POINTER(PSID),  # _Out_opt_ ppsidOwner
    ctypes.POINTER(PSID),  # _Out_opt_ ppsidGroup
    ctypes.POINTER(PACL),  # _Out_opt_ ppDacl
    ctypes.POINTER(PACL),  # _Out_opt_ ppSacl
    ctypes.POINTER(PSECURITY_DESCRIPTOR)) # _Out_opt_ ppSecurityDescriptor

functions

职能

def look_up_account_sid(sid, system_name=None):
    SIZE = 256
    name = ctypes.create_unicode_buffer(SIZE)
    domain = ctypes.create_unicode_buffer(SIZE)
    cch_name = wintypes.DWORD(SIZE)
    cch_domain = wintypes.DWORD(SIZE)
    sid_type = SID_NAME_USE()
    advapi32.LookupAccountSidW(system_name, sid, name, ctypes.byref(cch_name),
        domain, ctypes.byref(cch_domain), ctypes.byref(sid_type))
    return name.value, domain.value, sid_type

def get_file_security(filename, request=_DEFAULT_SECURITY_INFORMATION):
    # N.B. This query may fail with ERROR_INVALID_FUNCTION
    # for some filesystems.
    pSD = PSECURITY_DESCRIPTOR(needs_free=True)
    error = advapi32.GetNamedSecurityInfoW(filename, SE_FILE_OBJECT, request,
                ctypes.byref(pSD.pOwner), ctypes.byref(pSD.pGroup),
                ctypes.byref(pSD.pDacl), ctypes.byref(pSD.pSacl),
                ctypes.byref(pSD))
    if error != 0:
        raise ctypes.WinError(error)
    return pSD

example usage

示例用法

if __name__ == '__main__':
    import os, sys

    if len(sys.argv) < 2:
        script_name = os.path.basename(__file__)
        sys.exit('usage: {} filename'.format(script_name))

    filename = sys.argv[1]
    if isinstance(filename, bytes):
        if hasattr(os, 'fsdecode'):
            filename = os.fsdecode(filename)
        else:
            filename = filename.decode(sys.getfilesystemencoding())

    pSD = get_file_security(filename)
    owner_name, owner_domain, owner_sid_type = pSD.get_owner()
    if owner_domain:
        owner_name = '{}\{}'.format(owner_domain, owner_name)

    print("Path : {}".format(filename))
    print("Owner: {} ({})".format(owner_name, owner_sid_type))
    print("SID  : {}".format(pSD.pOwner))

example output

示例输出

Path : C:\Users
Owner: NT AUTHORITY\SYSTEM (WellKnownGroup)
SID  : S-1-5-18

Path : C:\ProgramData
Owner: NT AUTHORITY\SYSTEM (WellKnownGroup)
SID  : S-1-5-18

Path : C:\Program Files
Owner: NT SERVICE\TrustedInstaller (WellKnownGroup)
SID  : S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464

Path : C:\Windows
Owner: NT SERVICE\TrustedInstaller (WellKnownGroup)
SID  : S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464

回答by TJD

You could invoke a windows shell command "dir /q" and parse the output to find owners.

您可以调用 Windows shell 命令“dir /q”并解析输出以查找所有者。

subprocess.call("dir /q", shell=True)

回答by Enrico Ferreguti

This seem to be ok even on python 3 adjusting brackets on print http://timgolden.me.uk/python/win32_how_do_i/get-the-owner-of-a-file.html

即使在 python 3 上调整括号上的打印http://timgolden.me.uk/python/win32_how_do_i/get-the-owner-of-a-file.html也似乎没问题