Howto determine file owner on windows using python without pywin32

前端 未结 3 1047
别跟我提以往
别跟我提以往 2020-12-06 13:17

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

While I found a solution using pywin32 but I am hesitant to use it, as

相关标签:
3条回答
  • 2020-12-06 13:42

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

    subprocess.call("dir /q", shell=True)
    
    0 讨论(0)
  • 2020-12-06 13:43

    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

    0 讨论(0)
  • 2020-12-06 13:54

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

    ctypes and classes

    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
    
    0 讨论(0)
提交回复
热议问题