[python-win32] Using win32file.CreateDirectory including setting
permissions
David W. Harks
dave at psys.org
Fri Jun 13 07:18:18 EDT 2003
ACLs on Windows are interesting; I found that using the ADsSecurity DLL from
the ADSI SDK made life significantly easier...
Here's a Python module that does very simple permissions. (i.e. it's not
perfect yet, and indeed the "ALL" permission is a hack.)
This is designed for Windows 2000, and properly handles the ordering of the
ACEs.
Good luck!
dave
--------------code begins here-----------------
# ACL.py
# Wrap the ADsSecurity interface to ACLs in a pretty package.
# Dave Harks <dave at psys.org>
#
# Requires the ADsSecurity DLL
import win32com.client
import string
# Access Right constants
ADS_RIGHT_DELETE = 0x10000
ADS_RIGHT_READ_CONTROL = 0x20000
ADS_RIGHT_WRITE_DAC = 0x40000
ADS_RIGHT_WRITE_OWNER = 0x80000
ADS_RIGHT_SYNCHRONIZE = 0x100000
ADS_RIGHT_ACCESS_SYSTEM_SECURITY = 0x1000000
ADS_RIGHT_GENERIC_READ = 0x80000000
ADS_RIGHT_GENERIC_WRITE = 0x40000000
ADS_RIGHT_GENERIC_EXECUTE = 0x20000000
ADS_RIGHT_GENERIC_ALL = 0x10000000
ADS_RIGHT_DS_CREATE_CHILD = 0x1
ADS_RIGHT_DS_DELETE_CHILD = 0x2
ADS_RIGHT_ACTRL_DS_LIST = 0x4
ADS_RIGHT_DS_SELF = 0x8
ADS_RIGHT_DS_READ_PROP = 0x10
ADS_RIGHT_DS_WRITE_PROP = 0x20
ADS_RIGHT_DS_DELETE_TREE = 0x40
ADS_RIGHT_DS_LIST_OBJECT = 0x80
ADS_RIGHT_DS_CONTROL_ACCESS = 0x100
#ACETYPE constants
ADS_ACETYPE_ACCESS_ALLOWED = 0
ADS_ACETYPE_ACCESS_DENIED = 1
ADS_ACETYPE_SYSTEM_AUDIT = 0x2
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 0x5
ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6
ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 0x7
ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 0x8
#AceFlag constants
ADS_ACEFLAG_INHERIT_ACE = 0x2
ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = 0x4
ADS_ACEFLAG_INHERIT_ONLY_ACE = 0x8
ADS_ACEFLAG_INHERITED_ACE = 0x10
ADS_ACEFLAG_VALID_INHERIT_FLAGS = 0x1f
ADS_ACEFLAG_SUCCESSFUL_ACCESS = 0x40
ADS_ACEFLAG_FAILED_ACCESS = 0x80
class ACL:
"""Encapsulates the most common ACL operations.
showACL() - list the ACE entries in an ACL
addACL(trustee, access, type) - add an ACE.
trustee = NT username (CUIS\harksdw)
access = access mask, a string containing:
r = read
w = write
x = execute
a = all (full control)
type = 0 for Allow, 1 for Deny
"""
def __init__(self, path):
self.sec = win32com.client.Dispatch("ADsSecurity")
self.mySD = self.sec.GetSecurityDescriptor(path)
def showACL(self):
"""Prints a listing of ACEs in a DACL."""
for ace in self.mySD.DiscretionaryAcl:
print str(ace.Trustee), str(ace.AceType), hex(ace.AccessMask),
hex(ace.AceFlags)
def reorderACL(self):
"""Ensure that the ACL entries are in the proper order."""
objDacl = self.mySD.DiscretionaryAcl
# we have to get two copies, since the reset() function isn't
implemented yet as of this code
objDaclX = self.mySD.DiscretionaryAcl
# Create the ACL Objects.
newDACL = win32com.client.Dispatch("AccessControlList")
ImpDenyDacl = win32com.client.Dispatch("AccessControlList")
ImpDenyObjectDacl = win32com.client.Dispatch("AccessControlList")
ImpAllowDacl = win32com.client.Dispatch("AccessControlList")
ImpAllowObjectDacl = win32com.client.Dispatch("AccessControlList")
# inherited permissions go last, so start with the local ones
for ace in objDacl:
if ( ace.AceFlags & ADS_ACEFLAG_INHERITED_ACE ) == 0:
if ace.AceType == ADS_ACETYPE_ACCESS_DENIED:
ImpDenyDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_DENIED_OBJECT:
ImpDenyObjectDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_ALLOWED:
ImpAllowDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_ALLOWED_OBJECT:
ImpAllowObjectDacl.AddAce(ace)
# now do the inherited ones
for ace in objDaclX:
if ( ace.AceFlags & ADS_ACEFLAG_INHERITED_ACE ) ==
ADS_ACEFLAG_INHERITED_ACE:
if ace.AceType == ADS_ACETYPE_ACCESS_DENIED:
ImpDenyDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_DENIED_OBJECT:
ImpDenyObjectDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_ALLOWED:
ImpAllowDacl.AddAce(ace)
elif ace.AceType == ADS_ACETYPE_ACCESS_ALLOWED_OBJECT:
ImpAllowObjectDacl.AddAce(ace)
#Combine the ACEs in the Proper Order
#Implicit Deny
#Implicit Deny Object
#Implicit Allow
#Implicit Allow Object
#Implicit Deny.
for ace in ImpDenyDacl:
newDACL.AddAce(ace)
# Implicit Deny Object.
for ace in ImpDenyObjectDacl:
newDACL.AddAce(ace)
# Implicit Allow.
for ace in ImpAllowDacl:
newDACL.AddAce(ace)
# Implicit Allow Object.
for ace in ImpAllowObjectDacl:
newDACL.AddAce(ace)
#Set the Appropriate revision level for the DACL.
newDACL.AclRevision = objDacl.AclRevision
# Set properly ordered DACL.
self.mySD.DiscretionaryAcl = newDACL
try:
self.sec.SetSecurityDescriptor(self.mySD)
except:
print "Error setting security descriptor."
def addACE(self, trustee, access, type):
"""Add an Access Control Entry."""
dacl = self.mySD.DiscretionaryAcl
newACE = win32com.client.Dispatch("AccessControlEntry")
newACE.Trustee = trustee
newACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE | 0x1
access = string.lower(access)
accessList = []
myMask = 0
if string.find(access, 'a') >= 0:
#accessList.append(ADS_RIGHT_GENERIC_ALL)
# For now, 'til we understand the Access mask format better, use
this.
accessList.append(0x1f01ff)
else:
if string.find(access, 'r') >= 0:
accessList.append(ADS_RIGHT_GENERIC_READ)
if string.find(access, 'w') >= 0:
accessList.append(ADS_RIGHT_GENERIC_WRITE)
if string.find(access, 'x') >= 0:
accessList.append(ADS_RIGHT_GENERIC_EXECUTE)
# build an access mask from the access list
for mask in accessList:
myMask = myMask | mask
#print hex(myMask)
newACE.AccessMask = myMask
# Set the ACE type...don't depend on the ADS_ constants not changing
if type == 0:
newACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED
elif type == 1:
newACE.AceType = ADS_ACETYPE_ACCESS_DENIED
# Save the info back to the object
dacl.AddACE(newACE)
self.mySD.DiscretionaryAcl = dacl
try:
self.sec.SetSecurityDescriptor(self.mySD)
except:
print "Error setting Security Descriptor for " + trustee + ":" +
access
else:
self.reorderACL()
---------------code ends here-----------------
On Wednesday 11 June 2003 5:38 pm, Alex Willmer expounded thusly:
> Alex Willmer wrote:
> > win32file.CreateDirectory(r'c:\test42',sa)
> >
> > My problem is that I need users to have 'Full Control' of the directory,
> > as reported by the properties dialog of the directory. The
> > win32file.FILE_ALL_ACCESS doesn't achieve this, it reports the directory
> > as having 'Special Access', with none of the checkboxes in the advanced
> > page ticked.
> >
> > What is the correct constant to pass to acl.AddAccessAllowedAce?
>
> OK, a little more playing reveals the following. C:\test43 was created
> manually and my account given full permission
>
> >>> import win32file, win32security, ntsecuritycon
> >>> sd =
>
> win32security.GetFileSecurity(r'c:\test42',win32security.DACL_SECURITY_INFO
>RMATION)
>
> >>> acl = sd.GetSecurityDescriptorDacl()
> >>> acl.GetAceCount()
>
> 1
>
> >>> acl.GetAce(0)
>
> ((0, 3), 2032127, <PySID object at 0x01112968>)
>
> >>> def bin(x): return ''.join([('0','1')[(x >> i) & 0x01] for i in
>
> range(31,-1,-1)])
> ...
>
> >>> bin(acl.GetAce(0)[1])
>
> '00000000000111110000000111111111'
>
> This all seems good so far, however:
> >>> sid = win32security.LookupAccountName('','alex')[0]
> >>> sa = win32security.SECURITY_ATTRIBUTES()
> >>> acl2 = win32security.ACL(128)
> >>> acl2.AddAccessAllowedAce(x, sid)
> >>> sa.SetSecurityDescriptorDacl(1,acl2,0)
> >>> win32file.CreateDirectory(r'c:\test44',sa)
> >>> win32file.FILE_ALL_ACCESS
>
> 2032127
>
> >>> win32file.FILE_ALL_ACCESS==x
>
> 1
>
> Looking at c:\test44 with explorer shows that the permissions are the
> same as test42, win32file.FILE_ALL_ACCESS appears to have been the
> correct constant all along. Obviously I'm calling the functions wrongly,
> or missing a step.
>
> So my question now has to be, does anyone have an example the correct
> code for creating a directory, and giving a given user full permission
> as if it had been created with explorer and that user being given 'Full
> Control'?
>
> Any help would be greatly appreciated.
>
> Sincerely
>
> Alex Willmer
>
>
> _______________________________________________
> Python-win32 mailing list
> Python-win32 at python.org
> http://mail.python.org/mailman/listinfo/python-win32
--
David W. Harks <dave at psys.org> http://dwblog.psys.org
More information about the Python-win32
mailing list