如何使用Python在Windows上授权/拒绝对目录的写访问?

Jon*_*let 3 python windows winapi authorization

我希望能够授权或拒绝对Windows XP及更高版本上特定目录的写访问。

我尝试了以下方法,但它们都不起作用:

  • os.chmod():只能指定文件只读属性,请参见Python的文档
  • win32api.SetFileAttribute() FILE_ATTRIBUTE_READONLY:只读文件。[...]在目录中不使用此属性,请参见MSDN的SetFileAttribute

看来我唯一的选择就是访问和更新“ 安全信息 ”,我已经尝试了好几个小时才能完成一些工作,但收效甚微(我对Win32 API确实不熟悉)。

关于如何做到这一点的任何想法?

Vyk*_*tor 5

这只是具有挑战性的事情。我从这个非常好的答案开始,它可以帮助您解决类似问题。

您可以首先列出目录的ACL,可以使用以下代码完成此操作:

import win32security
import ntsecuritycon as con

FILENAME = r'D:\tmp\acc_test' 

sd = win32security.GetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()

ace_count = dacl.GetAceCount()
print('Ace count:', ace_count)

for i in range(0, ace_count):
    rev, access, usersid = dacl.GetAce(i)
    user, group, type  = win32security.LookupAccountSid('', usersid)
    print('User: {}/{}'.format(group, user), rev, access)
Run Code Online (Sandbox Code Playgroud)

您可以找到PyACL.GetAceCount()返回ACE数量的方法。

GetAce(i)函数返回ACCESS_ALLOWED_ACE作为tuple

现在,您可以阅读旧的ACE,删除旧的 ACE 非常简单:

for i in range(0, ace_count):
    dacl.DeleteAce(0)
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过调用AddAccessAllowedAceEx()[ MSDN ] 添加特权:

userx, domain, type = win32security.LookupAccountName ("", "your.user")
usery, domain, type = win32security.LookupAccountName ("", "other.user")

dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 3, 2032127, userx) # Full control
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 3, 1179785, usery) # Read only

sd.SetSecurityDescriptorDacl(1, dacl, 0)   # may not be necessary
win32security.SetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION, sd)
Run Code Online (Sandbox Code Playgroud)

我已经获取了数字32032127并且1179785从脚本的前半部分列出了这些(在运行脚本之前,我已经在Explorer-> Right Click-> Properties-> Security-> Advanced中设置了权限):

资源管理器->右键->属性->安全->高级

只是从http://technet.microsoft.com/借来的说明性图像

User: DOMAIN/user (0, 3) 2032127
User: DOMAIN/user2 (0, 3) 1179785
Run Code Online (Sandbox Code Playgroud)

但这对应于:

  • 3- >OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE
  • 2032127 - > FILE_ALL_ACCESS(当然,实际上con.FILE_ALL_ACCESS = 2032639,但是一旦你把它在文件和读取它,你会得到2032127 ;所不同的是512 - 0200 -我还没有发现中恒ntsecuritycon.py/file security permissions
  • 1179785- >FILE_GENERIC_READ

您也可以删除,更改或删除访问权限,但这对您来说应该是一个坚实的开端。


TL; DR-代码

import win32security
import ntsecuritycon as con

FILENAME = r'D:\tmp\acc_test'

userx, domain, type = win32security.LookupAccountName ("", "your.user")
usery, domain, type = win32security.LookupAccountName ("", "other.user")

sd = win32security.GetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()

ace_count = dacl.GetAceCount()
print('Ace count:', ace_count)

# Listing
for i in range(0, ace_count):
    rev, access, usersid = dacl.GetAce(i)
    user, group, type  = win32security.LookupAccountSid('', usersid)

    print('User: {}/{}'.format(group, user), rev, access)

# Removing the old ones
for i in range(0, ace_count):
    dacl.DeleteAce(0)

# Add full control for user x
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 
    con.OBJECT_INHERIT_ACE|con.CONTAINER_INHERIT_ACE, con.FILE_ALL_ACCESS, userx)

# Add read only access for user y
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 
    con.OBJECT_INHERIT_ACE|con.CONTAINER_INHERIT_ACE, con.FILE_GENERIC_READ, usery)

sd.SetSecurityDescriptorDacl(1, dacl, 0)   # may not be necessary
win32security.SetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION, sd)
Run Code Online (Sandbox Code Playgroud)

迷你实用程序,可完整列出ACE

我只是编写了用于解析所有文件ACE的小脚本:

import win32security
import ntsecuritycon as con
import sys


# List of all file masks that are interesting
ACCESS_MASKS = ['FILE_READ_DATA', 'FILE_LIST_DIRECTORY', 'FILE_WRITE_DATA', 'FILE_ADD_FILE', 
                     'FILE_APPEND_DATA', 'FILE_ADD_SUBDIRECTORY', 'FILE_CREATE_PIPE_INSTANCE', 'FILE_READ_EA',
                     'FILE_WRITE_EA', 'FILE_EXECUTE', 'FILE_TRAVERSE', 'FILE_DELETE_CHILD', 
                     'FILE_READ_ATTRIBUTES', 'FILE_WRITE_ATTRIBUTES', 'FILE_ALL_ACCESS', 'FILE_GENERIC_READ',
                     'FILE_GENERIC_WRITE', 'FILE_GENERIC_EXECUTE'] 

# List of all inheritance flags
ACE_FLAGS = ['OBJECT_INHERIT_ACE', 'CONTAINER_INHERIT_ACE', 'NO_PROPAGATE_INHERIT_ACE', 'INHERIT_ONLY_ACE']

# List of all ACE types
ACE_TYPES = ['ACCESS_MIN_MS_ACE_TYPE', 'ACCESS_ALLOWED_ACE_TYPE', 'ACCESS_DENIED_ACE_TYPE', 'SYSTEM_AUDIT_ACE_TYPE',
             'SYSTEM_ALARM_ACE_TYPE', 'ACCESS_MAX_MS_V2_ACE_TYPE', 'ACCESS_ALLOWED_COMPOUND_ACE_TYPE',
             'ACCESS_MAX_MS_V3_ACE_TYPE', 'ACCESS_MIN_MS_OBJECT_ACE_TYPE', 'ACCESS_ALLOWED_OBJECT_ACE_TYPE',
             'ACCESS_DENIED_OBJECT_ACE_TYPE', 'SYSTEM_AUDIT_OBJECT_ACE_TYPE', 'SYSTEM_ALARM_OBJECT_ACE_TYPE',
             'ACCESS_MAX_MS_OBJECT_ACE_TYPE', 'ACCESS_MAX_MS_V4_ACE_TYPE', 'ACCESS_MAX_MS_ACE_TYPE',
             'ACCESS_ALLOWED_CALLBACK_ACE_TYPE', 'ACCESS_DENIED_CALLBACK_ACE_TYPE', 'ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE',
             'ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE', 'SYSTEM_AUDIT_CALLBACK_ACE_TYPE', 'SYSTEM_ALARM_CALLBACK_ACE_TYPE',
             'SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE', 'SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE', 'SYSTEM_MANDATORY_LABEL_ACE_TYPE',
             'ACCESS_MAX_MS_V5_ACE_TYPE']

################################################################################
def get_ace_types_str(ace_type):
    ''' Yields all matching ACE types as strings
    '''
    for t in ACE_TYPES:
        if getattr(con, t) == ace_type:
            yield t

################################################################################
def get_ace_flags_str(ace_flag):
    ''' Yields all matching ACE flags as strings 
    '''
    for t in ACE_FLAGS:
        attr = getattr(con, t)
        if (attr & ace_flag) == attr:
            yield t

################################################################################
def get_access_mask_str(access_mask):
    ''' Yields all matching ACE flags as strings 
    '''
    for t in ACCESS_MASKS:
        attr = getattr(con, t)
        if (attr & access_mask) == attr:
            yield t

################################################################################
def list_file_ace(filename):
    ''' Method for listing of file ACEs
    '''

    # Load data
    sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
    dacl = sd.GetSecurityDescriptorDacl()     

    # Print ACE count
    ace_count = dacl.GetAceCount()
    print('File', filename, 'has', ace_count, 'ACEs')

    # Go trough individual ACEs
    for i in range(0, ace_count):
        (ace_type, ace_flag), access_mask, usersid = dacl.GetAce(i)
        user, group, usertype = win32security.LookupAccountSid('', usersid)

        print('\tUser: {}\\{}'.format(group, user))    
        print('\t\tACE Type ({}):'.format(ace_type), '; '.join(get_ace_types_str(ace_type))) 
        print('\t\tACE Flags ({}):'.format(ace_flag), ' | '.join(get_ace_flags_str(ace_flag)))
        print('\t\tAccess Mask ({}):'.format(access_mask), ' | '.join(get_access_mask_str(access_mask)))
        print()


################################################################################
# Execute with some defaults
if __name__ == '__main__':
    for filename in sys.argv[1:]:
        list_file_ace(filename)
        print()
Run Code Online (Sandbox Code Playgroud)

它打印出如下字符串:

D:\tmp>acc_list.py D:\tmp D:\tmp\main.bat
File D:\tmp has 8 ACEs
        User: BUILTIN\Administrators
                ACE Type (0): ACCESS_MIN_MS_ACE_TYPE; ACCESS_ALLOWED_ACE_TYPE
                ACE Flags (0):
                Access Mask (2032127): FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_ADD_FILE | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_CREATE_PIPE_INSTANCE | FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE | FILE_TRAVERSE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE

...
Run Code Online (Sandbox Code Playgroud)