<p>所以,我四处打探,试图了解到底发生了什么,我设法找到了与@Vyktor之前发布的内容非常相似的东西。在</p>
<p>我用<a href="https://code.google.com/p/pythonxy/source/browse/src/python/pywin32/PLATLIB/win32/Demos/security/setnamedsecurityinfo.py?repo=xy-27&r=b92705dfbb538e51c450cb5592e64acbe42c21d6" rel="nofollow">this example</a>找到了一些帮助。在</p>
<p>所以,我做的第一件事就是试图理解Windows设置的标志,当我用GUI手动更改安全信息时,我构建了一组函数来帮助我:</p>
<pre class="lang-python prettyprint-override"><code>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))
</code></pre>
<p>从那里,我得到了以下信息:</p>
^{pr2}$
<p>这个例子显示了我系统上的默认ACL+第一个ACL,它是我自己创建的,它拒绝在目录中写入。在</p>
<p>所以,使用前面的例子,我构建了这个:</p>
<pre><code>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)
</code></pre>
<p>与@Vyktor解决方案相反,我使用了一个“拒绝”ACE,拒绝写访问(而Vyktor添加了一个“允许只读”ACE)。在</p>
<p>我会错过一个合适的方法来删除这个ACE,这样我就可以在这个目录中再写一次了,但是我还没有真正去看。有一点很重要,“Denied”ACE的优先级高于“Allowed”ACE,因此我尝试了一种简单的方法,即使用与在<code>dacl.AddAccessDeniedAceEx()</code>完全相同的参数使用{<cd1>},但后者的优先级高于前一个,因此我仍然无法写入目录。在</p>