我希望能够授权或拒绝对Windows XP上特定目录的写访问权限。
我尝试了以下操作,但它们都不起作用:
os.chmod()
:只能指定文件只读属性,请参阅Python's doc win32api.SetFileAttribute()
FILE_ATTRIBUTE_READONLY:只读文件。 [...]目录不支持此属性,请参阅MSDN's SetFileAttribute 看起来我唯一的选择是访问和更新目录的“Security info”,我已经尝试了几个小时来完成这项工作而没有取得多大成功(我真的很陌生使用Win32 API)。
关于如何做到这一点的任何想法?
答案 0 :(得分:5)
这只是挑战性的事情。我从this really great answer开始,它可以帮助你做类似的事情。
您可以首先列出目录的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)
您可以找到返回ACE数量的方法PyACL.GetAceCount()
。
GetAce(i)
函数将ACCESS_ALLOWED_ACE
header作为tuple
返回:
ACE_HEADER
- 两个整数AceType
,AceFlags
- 试验和错误告诉我AceFlags
设置为11
表示继承权限和3
ACCESS_MASK
- 详细list here或ntsecuritycon.py
SID
现在您可以阅读旧的ACE,而deleting old ones非常简单:
for i in range(0, ace_count):
dacl.DeleteAce(0)
之后,您只需拨打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)
我从脚本前半部分的列表中获取了数字3
,2032127
和1179785
(在运行脚本之前,我在 Explorer中设置了权限 - >右键单击 - >属性 - >安全 - >高级):
只是从http://technet.microsoft.com/
借来的说明性图片User: DOMAIN/user (0, 3) 2032127
User: DOMAIN/user2 (0, 3) 1179785
但它对应于:
OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE
FILE_ALL_ACCESS
(实际上是con.FILE_ALL_ACCESS = 2032639
,但是一旦你将其应用到文件中并将其读回来,你将获得 2032127 ;差异是 512 - 0x0200 - 我在ntsecuritycon.py/file security permissions
)FILE_GENERIC_READ
您也可以删除访问权限,更改权限或将其删除,但这应该是非常可靠的开始。
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)
我刚刚编写了用于解析所有文件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()
打印出如下字符串:
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
...
答案 1 :(得分:0)
所以,通过喋喋不休并试图了解发生了什么,我找到了与@Vyktor之前发布的非常相似的东西。
我使用this example找到了一些帮助。
所以,我做的第一件事是尝试理解Windows在我用GUI手动更改安全信息时设置的标志,我构建了一组函数来帮助我:
import os
import win32con
import win32security
import win32process
import ntsecuritycon
d = "toto"
f = os.path.join(d, "foo")
def build_flags_map(*attrs, **kw):
mod = kw.get('mod', win32con)
r = {}
for attr in attrs:
value = getattr(mod, attr)
r[value] = attr
return r
ACE_TYPE = build_flags_map('ACCESS_ALLOWED_ACE_TYPE', 'ACCESS_DENIED_ACE_TYPE')
ACCESS_MASK = build_flags_map(
'GENERIC_WRITE', 'GENERIC_ALL', 'GENERIC_EXECUTE', 'GENERIC_READ',
'WRITE_OWNER', 'DELETE', 'READ_CONTROL', 'SYNCHRONIZE', 'WRITE_DAC',
'ACCESS_SYSTEM_SECURITY')
ACCESS_MASK_FILES = build_flags_map(
'FILE_ADD_FILE', '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',
mod=ntsecuritycon,
)
ACE_FLAGS = build_flags_map(
'CONTAINER_INHERIT_ACE', 'INHERITED_ACE', 'FAILED_ACCESS_ACE_FLAG',
'INHERIT_ONLY_ACE', 'OBJECT_INHERIT_ACE',
mod=win32security)
def display_flags(map, value):
r = []
for flag, name in map.items():
if flag & value:
r.append(name)
value = value - flag
if value != 0:
# We didn't specified all the flags in the mapping :(
r.append('(flags left 0x%x)' % value)
return r' | '.join(r)
def show_acls(path):
process_handler = win32process.GetCurrentProcess()
thread_handler = win32security.OpenProcessToken(
process_handler,
win32security.TOKEN_ALL_ACCESS)
current_sid = win32security.GetTokenInformation(thread_handler, win32security.TokenUser)[0]
desc = win32security.GetNamedSecurityInfo(
path,
win32security.SE_FILE_OBJECT,
win32security.DACL_SECURITY_INFORMATION)
dacl = desc.GetSecurityDescriptorDacl()
print("%d ACE on %s" % (dacl.GetAceCount(), path))
for i in range(0, dacl.GetAceCount()):
ace = dacl.GetAce(i)
(ace_type, ace_flags), ace_mask, ace_sid = ace
if ace_sid == current_sid:
user = "me"
else:
user = str(ace_sid)
print(" User: %s =>\n"
" ACE type: %s\n"
" ACE flags: %s\n"
" ACE mask: %s\n"
" Raw ACE: %r\n" % (
user,
ACE_TYPE[ace_type],
display_flags(ACE_FLAGS, ace_flags),
display_flags(ACCESS_MASK_FILES, ace_mask),
ace))
从那里,我得到以下信息:
7 ACE on toto
User: me =>
ACE type: ACCESS_DENIED_ACE_TYPE
ACE flags: CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
ACE mask: FILE_ADD_FILE | FILE_CREATE_PIPE_INSTANCE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA
Raw ACE: ((1, 3), 278, <PySID object at 0x00B02148>)
User: me =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE
ACE mask: FILE_TRAVERSE | FILE_LIST_DIRECTORY | FILE_ADD_FILE | FILE_CREATE_PIPE_INSTANCE | FILE_READ_EA | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES | FILE_GENERIC_EXECUTE | FILE_WRITE_EA | FILE_ALL_ACCESS | (flags left 0x-12039f)
Raw ACE: ((0, 16), 2032127, <PySID object at 0x00A6FBF0>)
User: me =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
ACE mask: (flags left 0x10000000)
Raw ACE: ((0, 27), 268435456, <PySID object at 0x00B02148>)
User: PySID:S-1-5-18 =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE
ACE mask: FILE_TRAVERSE | FILE_LIST_DIRECTORY | FILE_ADD_FILE | FILE_CREATE_PIPE_INSTANCE | FILE_READ_EA | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES | FILE_GENERIC_EXECUTE | FILE_WRITE_EA | FILE_ALL_ACCESS | (flags left 0x-12039f)
Raw ACE: ((0, 16), 2032127, <PySID object at 0x00A6FBF0>)
User: PySID:S-1-5-18 =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
ACE mask: (flags left 0x10000000)
Raw ACE: ((0, 27), 268435456, <PySID object at 0x00B02148>)
User: PySID:S-1-5-32-544 =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE
ACE mask: FILE_TRAVERSE | FILE_LIST_DIRECTORY | FILE_ADD_FILE | FILE_CREATE_PIPE_INSTANCE | FILE_READ_EA | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES | FILE_GENERIC_EXECUTE | FILE_WRITE_EA | FILE_ALL_ACCESS | (flags left 0x-12039f)
Raw ACE: ((0, 16), 2032127, <PySID object at 0x00A6FBF0>)
User: PySID:S-1-5-32-544 =>
ACE type: ACCESS_ALLOWED_ACE_TYPE
ACE flags: INHERITED_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
ACE mask: (flags left 0x10000000)
Raw ACE: ((0, 27), 268435456, <PySID object at 0x00B02148>)
此示例显示了我在系统上的默认ACL +第一个,我自己创建的那个,并且拒绝在目录上写入。
所以,使用之前的例子,我构建了这个:
def pipe_str_flags(map, *flags):
r = 0
reverse_map = dict((value, key) for key, value in map.items())
for flag in flags:
r = r | reverse_map[flag]
return r
def forbid_write(path):
security_info = win32security.DACL_SECURITY_INFORMATION
process_handler = win32process.GetCurrentProcess()
thread_handler = win32security.OpenProcessToken(
process_handler,
win32security.TOKEN_ALL_ACCESS)
desc = win32security.GetNamedSecurityInfo(
path,
win32security.SE_FILE_OBJECT,
security_info)
current_sid = win32security.GetTokenInformation(thread_handler, win32security.TokenUser)[0]
dacl = desc.GetSecurityDescriptorDacl()
mask = pipe_str_flags(ACCESS_MASK_FILES,
'FILE_ADD_FILE',
'FILE_CREATE_PIPE_INSTANCE',
'FILE_WRITE_ATTRIBUTES',
'FILE_WRITE_EA')
ace_flags = pipe_str_flags(ACE_FLAGS,
'CONTAINER_INHERIT_ACE',
'OBJECT_INHERIT_ACE')
dacl.AddAccessDeniedAceEx(
dacl.GetAclRevision(),
ace_flags,
mask,
current_sid)
win32security.SetNamedSecurityInfo(
path,
win32security.SE_FILE_OBJECT,
security_info,
None,
None,
dacl,
None)
与@Vyktor解决方案相反,我使用&#34;拒绝&#34; ACE,拒绝写访问(而Vyktor添加了&#34;允许只读&#34; ACE)。
我错过了一个正确的方法来删除这个ACE,所以我可以在这个目录中再次写,但我还没看到。有一件重要的事情是&#34;拒绝&#34; ACE优先于&#34;允许&#34; ACE,所以我尝试了使用dacl.AddAccessAllowedAceEx()
的天真方式,其参数与我在dacl.AddAccessDeniedAceEx()
上使用的参数完全相同,但后者优先于前者,所以我仍然可以写进目录。