[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