<p>这是一件很有挑战性的事情。我从<a href="https://stackoverflow.com/a/12168268/1149736">this really great answer</a>开始,它可以帮助您处理类似的问题。在</p>
<p>您可以先列出目录的ACL,这可以使用以下代码完成:</p>
<pre class="lang-python prettyprint-override"><code>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)
</code></pre>
<p>您可以找到方法<a href="http://docs.activestate.com/activepython/3.2/pywin32/PyACL__GetAceCount_meth.html" rel="nofollow noreferrer">^{<cd1>}</a>,它返回ACE的数量。在</p>
<p><a href="http://docs.activestate.com/activepython/3.2/pywin32/PyACL__GetAce_meth.html" rel="nofollow noreferrer">^{<cd2>}</a>函数将<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa374847(v=vs.85).aspx" rel="nofollow noreferrer">^{<cd3>} header</a>作为<code>tuple</code>返回:</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa374919(v=vs.85).aspx" rel="nofollow noreferrer">^{<cd5>}</a>-两个整数<code>AceType</code>,<code>AceFlags</code>-反复试验表明,<code>AceFlags</code>设置为<code>11</code>意味着继承特权,<code>3</code>不是继承的</li>
<li><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa374892(v=vs.85).aspx" rel="nofollow noreferrer">^{<cd11>}</a>-详细<a href="https://stackoverflow.com/a/21321743/1149736">list here</a>或<a href="http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/win32/lib/ntsecuritycon.py.html" rel="nofollow noreferrer">^{<cd12>}</a></li>
<li><code>SID</code></li>
</ul>
<p>现在您可以阅读旧的ACE,并且<a href="http://docs.activestate.com/activepython/3.2/pywin32/PyACL__DeleteAce_meth.html" rel="nofollow noreferrer">deleting old ones</a>非常简单:</p>
^{pr2}$
<p>然后,您可以通过调用<a href="http://docs.activestate.com/activepython/3.2/pywin32/PyACL__AddAccessAllowedAceEx_meth.html" rel="nofollow noreferrer">^{<cd14>}</a>[<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa374951(v=vs.85).aspx" rel="nofollow noreferrer">MSDN</a>]来添加特权:</p>
<pre class="lang-python prettyprint-override"><code>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)
</code></pre>
<p>我从脚本前半部分的列表中获取了编号<code>3</code>、<code>2032127</code>和{<cd17>}(在运行脚本之前,我在<em>Explorer->;右键单击->;Properties->;Security->;Advanced</em>中设置了权限):</p>
<p>{1美元^</p>
<p><sup>只是借用了<a href="http://technet.microsoft.com/" rel="nofollow noreferrer">http://technet.microsoft.com/</a>的说明性图片</sup></p>
<pre class="lang-none prettyprint-override"><code>User: DOMAIN/user (0, 3) 2032127
User: DOMAIN/user2 (0, 3) 1179785
</code></pre>
<p>但它对应于:</p>
<ul>
<li><em>3</em>->;<code>OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE</code></li>
<li><em>2032127</em>->;<code>FILE_ALL_ACCESS</code>(实际上是<code>con.FILE_ALL_ACCESS = 2032639</code>,但是一旦你把它应用到文件中并读回它,你就会得到<em>2032127</em>;区别是<em>512-0x0200</em>——我在<a href="http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/win32/lib/ntsecuritycon.py.html#0021" rel="nofollow noreferrer">^{<cd21>}</a>中没有找到的常数)</li>
<li><em>1179785</em>->;<code>FILE_GENERIC_READ</code></li>
</ul>
<p>你也可以删除访问,更改或删除它,但这应该是一个非常坚实的开始。在</p>
<hr/>
<h3>TL;DR-代码</h3>
<pre class="lang-python prettyprint-override"><code>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)
</code></pre>
<hr/>
<h3>完整ACE列表的迷你实用程序</h3>
<p>我刚刚写了一个小脚本来解析所有的文件ace:</p>
<pre class="lang-python prettyprint-override"><code>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()
</code></pre>
<p>它打印出这样的字符串:</p>
<pre class="lang-none prettyprint-override"><code>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
...
</code></pre>