<CODE>
Private Sub SetNTFSPermissions(ByVal strFilePath As String, _
ByVal strTrustee As String, _
ByVal strPermissions As String, _
Optional ByVal blnDenyAccess As Boolean = False, _
Optional ByVal blnIsFolder As Boolean = True)
On Error GoTo errSetNTFSPermissions
Const METHOD_NAME As String = "SetNTFSPermissions"
Const METHOD_SIG As String = MODULE_NAME & "." & METHOD_NAME
Dim lngAccessMask As Long
Dim lngACEType As Long
Dim lngACEFlags As Long
Dim i As Integer
If blnDenyAccess Then
lngACEType = ADS_ACETYPE_ACCESS_DENIED
Else
lngACEType = ADS_ACETYPE_ACCESS_ALLOWED
If strPermissions <> Empty Then lngAccessMask =
ADS_RIGHT_SYNCHRONIZE
End If
For i = 1 To Len(strPermissions)
Select Case UCase(Mid(strPermissions, i, 1))
Case "R"
lngAccessMask = lngAccessMask Or ADS_RIGHT_READ_CONTROL _
Or ADS_RIGHT_DS_LIST_OBJECT _
Or ADS_RIGHT_DS_SELF _
Or ADS_RIGHT_DS_CREATE_CHILD
Case "X"
lngAccessMask = lngAccessMask Or ADS_RIGHT_DS_WRITE_PROP
Case "W"
lngAccessMask = lngAccessMask Or ADS_RIGHT_DS_DELETE_CHILD _
Or ADS_RIGHT_ACTRL_DS_LIST _
Or ADS_RIGHT_DS_READ_PROP _
Or ADS_RIGHT_DS_CONTROL_ACCESS
Case "D"
lngAccessMask = lngAccessMask Or ADS_RIGHT_DELETE
Case "F"
lngAccessMask = lngAccessMask Or ADS_RIGHT_DELETE _
Or ADS_RIGHT_READ_CONTROL _
Or ADS_RIGHT_WRITE_DAC _
Or ADS_RIGHT_SYNCHRONIZE _
Or ADS_RIGHT_WRITE_OWNER _
Or ADS_RIGHT_DS_LIST_OBJECT _
Or ADS_RIGHT_DS_CREATE_CHILD _
Or ADS_RIGHT_DS_DELETE_CHILD _
Or ADS_RIGHT_ACTRL_DS_LIST _
Or ADS_RIGHT_DS_SELF _
Or ADS_RIGHT_DS_READ_PROP _
Or ADS_RIGHT_DS_WRITE_PROP _
Or ADS_RIGHT_DS_DELETE_TREE _
Or ADS_RIGHT_DS_LIST_OBJECT _
Or ADS_RIGHT_DS_CONTROL_ACCESS
End Select
Next
If blnIsFolder Then
lngACEFlags = ADS_ACEFLAG_INHERIT_ACE Or 1
End If
If SetNTFSAccessRight(strFilePath, _
lngAccessMask, _
lngACEType, _
lngACEFlags, _
strTrustee) Then
MsgBox "Good News..."
Else
MsgBox "Bad News..."
End Id
Exit Sub
errSetNTFSPermissions:
WriteToErrorLog METHOD_NAME, Err.Source, Err.Number, Err.Description
Resume Next
End Sub
Public Function SetNTFSAccessRight(ByVal strFilePath As String, _
ByVal lngAccessRights As Long, _
ByVal lngACEType As Long, _
ByVal lngACEFlags As Long, _
ByVal strTrustee As String) As Boolean
On Error GoTo errSetNTFSAccessRight
Const METHOD_NAME As String = "SetNTFSAccessRight"
Const METHOD_SIG As String = MODULE_NAME & "." & METHOD_NAME
Dim objSecurity As New ActiveDs.ADsSecurityUtility
Dim objSecDesc As ActiveDs.SecurityDescriptor
Dim objDACL As ActiveDs.AccessControlList
Dim objOldACE As ActiveDs.AccessControlEntry
Dim objACE As New ActiveDs.AccessControlEntry
Set objSecDesc = objSecurity.GetSecurityDescriptor(strFilePath,
ADS_PATH_FILE, ADS_SD_FORMAT_IID)
Set objDACL = objSecDesc.DiscretionaryAcl
For Each objOldACE In objDACL
If objOldACE.Trustee = strTrustee AND objOldACE.AceType = lngACEType
Then
Call objDACL.RemoveAce(objOldACE)
End If
Next
If lngAccessRights Then
With objACE
.AccessMask = lngAccessRights
.AceType = lngACEType
.AceFlags = lngACEFlags
.Trustee = strTrustee
End With
With objDACL
.AclRevision = ACL_REVISION_DS
.AddAce objACE
End With
End If
objSecDesc.DiscretionaryAcl = objDACL
objSecurity.SetSecurityDescriptor strFilePath, ADS_PATH_FILE,
objSecDesc, ADS_SD_FORMAT_IID
SetNTFSAccessRight = True
Exit Function
errSetNTFSAccessRight:
WriteToErrorLog METHOD_SIG, Err.Source, Err.Number, Err.Description
Set objSecurity = Nothing
Set objSecDesc = Nothing
Set objDACL = Nothing
Set objACE = Nothing
SetNTFSAccessRight = False
End Function
</CODE>
--
John Harvey
Light moves faster than sound.
This is why I sometimes appear bright...
until I open my mouth.
> If you are running the code from XP, look closely at IADsSecurityUtility,
> this object will do a number of things for you. It will properly order
the
> ACL, push inheritance down the folder food chain and will return you an
> IADsSecurityDescriptor object, much easier to work with than trying to
> learn the cryptic WMI bind syntax.
>
> Sincerely,
> Max Vaughn [MS]
> Microsoft Developer Support
This would be most useful, as enumerating and assigning the same permissions
on all children of a folder is tedious. I assume there must be a way of
"refreshing" the subtree to "pick up" the inherited ACE...
Thanks in advance for your kind help...It is truly appreciated!
John
--
John Harvey
Light moves faster than sound.
This is why I sometimes appear bright...
until I open my mouth.
"John Harvey" <jcha...@NOaebcSPAM.com> wrote in message
news:%23PC90bI...@TK2MSFTNGP09.phx.gbl...
> I am having a bit of a problem setting NTFS permissions, in that they
don't
> seem to propagate down the subdirectories after I set them, though
creating
> new files/foders seems to inherit the permission I set just fine. What am
I
> missing...I've included my code below...
To get ACEs to propagate on win2k you are going to have to do one of two
things:
1. Propagate them your self which will be a very time consuming operation
because of the way that the ADSI peroperty cache works.
2. Use SetNamedSecurityInfo to force the propagation for you. This will
take more time to developer because you cannot call an API from VBS, you
would have to wrap it a com wrapper.
I made a post in the past that contained a copy of a zip file that contains
the source to a com object that could be called from VBS or VB to force
propagation, try searching for other posts related to this topic. If you
cannot find it, start a new thread and I will post the zip file once again.
Sincerely,
Max Vaughn [MS]
Microsoft Developer Support
Disclaimer: This posting is provided "AS IS" with no warranties, and
confers no rights. You assume all risk for your use.
Thanks for the help!
John
--
John Harvey
Light moves faster than sound.
This is why I sometimes appear bright...
until I open my mouth.
"Max L. Vaughn [MSFT]" <ma...@online.microsoft.com> wrote in message
news:6pomLVPw...@cpmsftngxa07.phx.gbl...
Every time you use ADsSecurity.dll to retrieve a security descriptor, the
ADSI property cache converts the binary SD into an IADsSecurityDescriptor
interface. This takes time.
This conversion is done every time get a security descriptor and every time
you put it back into the ADSI property Cache.
This will need to be done on every file and folder in the tree.
If you convert the IADsSecurityDescriptor to binary and use the APIs to
remove the DACL from the SD, then you can use the SetNamedSecurityInfo API
on the root folder and all the SDs down the line will be modified to
include the inheritable ACE. This method is at least 100 times faster
than enumerating all the files and folders and recursing down, retrieving
the SDs and modifying them as you go.
Sincerely,
Max Vaughn [MS]
Microsoft Developer Support
Disclaimer: This posting is provided "AS IS" with no warranties, and
confers no rights. You assume all risk for your use.
Here is some code for calling SetNamedSecurityInfo, it works with a
registry key, but you can modify it to work with a file.
Const ADS_RIGHTS_RGY_KEY_READ = &H20019
'
' Declaration for GetNamedSecurityInfo
'
'DWORD GetNamedSecurityInfo(
' LPTSTR pObjectName,
' SE_OBJECT_TYPE ObjectType,
' SECURITY_INFORMATION SecurityInfo,
' PSID* ppsidOwner,
' PSID* ppsidGroup,
' PACL* ppDacl,
' PACL* ppSacl,
' PSECURITY_DESCRIPTOR* ppSecurityDescriptor
');
Private Declare Function GetNamedSecurityInfoA Lib "advapi32.dll" ( _
ByVal strObjectName As String, _
ByVal lObjectType As Long, _
ByVal lSecInfo As Long, _
ppSidOwner As Long, _
ppSidGroup As Long, _
ppDacl As Long, _
ppSacl As Long, _
ppSecurityDescriptor As Long _
) As Long
'
' Declaration for SetNamedSecurityInfo
'
'DWORD SetNamedSecurityInfo(
' LPTSTR pObjectName,
' SE_OBJECT_TYPE ObjectType,
' SECURITY_INFORMATION SecurityInfo,
' PSID psidOwner,
' PSID psidGroup,
' PACL pDacl,
' PACL pSacl
');
Private Declare Function SetNamedSecurityInfoA Lib "advapi32.dll" ( _
ByVal strObjectName As String, _
ByVal lObjectType As Long, _
ByVal lSecInfo As Long, _
ByVal pSidOwner As Long, _
ByVal psidGroup As Long, _
ByVal pDacl As Long, _
ByVal pSacl As Long _
) As Long
'
' Define SE_OBJECT_TYPE constants:
'
'typedef enum _SE_OBJECT_TYPE
'{
' SE_UNKNOWN_OBJECT_TYPE = 0,
' SE_FILE_OBJECT,
' SE_SERVICE,
' SE_PRINTER,
' SE_REGISTRY_KEY,
' SE_LMSHARE,
' SE_KERNEL_OBJECT,
' SE_WINDOW_OBJECT,
' SE_DS_OBJECT,
' SE_DS_OBJECT_ALL,
' SE_PROVIDER_DEFINED_OBJECT,
' SE_WMIGUID_OBJECT,
' SE_REGISTRY_WOW64_32KEY
'} SE_OBJECT
'
Const SE_UNKNOWN_OBJECT_TYPE = 0
Const SE_FILE_OBJECT = 1
Const SE_SERVICE = 2
Const SE_PRINTER = 3
Const SE_REGISTRY_KEY = 4
Const SE_LMSHARE = 5
Const SE_KERNEL_OBJECT = 6
Const SE_WINDOW_OBJECT = 7
Const SE_DS_OBJECT = 8
Const SE_DS_OBJECT_ALL = 9
Const SE_PROVIDER_DEFINED_OBJECT = 10
Const SE_WMIGUID_OBJECT = 11
Const SE_REGISTRY_WOW64_32KEY = 12
'
' SECURITY_INFORMATION constants
'
'typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION;
'
'#define OWNER_SECURITY_INFORMATION (0x00000001L)
'#define GROUP_SECURITY_INFORMATION (0x00000002L)
'#define DACL_SECURITY_INFORMATION (0x00000004L)
'#define SACL_SECURITY_INFORMATION (0x00000008L)
'
'#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L)
'#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L)
'#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L)
'#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L)
'
'typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION;
'
Const OWNER_SECURITY_INFORMATION = &H1
Const GROUP_SECURITY_INFORMATION = &H2
Const DACL_SECURITY_INFORMATION = &H4
Const SACL_SECURITY_INFORMATION = &H8
'
Const PROTECTED_DACL_SECURITY_INFORMATION = &H80000000
Const PROTECTED_SACL_SECURITY_INFORMATION = &H40000000
Const UNPROTECTED_DACL_SECURITY_INFORMATION = &H20000000
Const UNPROTECTED_SACL_SECURITY_INFORMATION = &H10000000
'
' Define the LocalFree function to release the memory
' allocated by GetNamedSecurityInfo
'
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As
Long
'
' Need GetLastError to retrieve additional error information
'
Private Declare Function GetLastError Lib "kernel32" () As Long
'
'
'
Dim sec As New ADsSecurity
Dim sd As IADsSecurityDescriptor
Dim dacl As IADsAccessControlList
Dim ace As IADsAccessControlEntry
Dim newAce As New AccessControlEntry
'
' Declare temporary ACLs for sorting the original
' ACL
'
Dim newdacl As New AccessControlList
Dim ImpDenyDacl As New AccessControlList
Dim InhDenyDacl As New AccessControlList
Dim ImpAllowDacl As New AccessControlList
Dim InhAllowDacl As New AccessControlList
Private Sub Command1_Click()
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("RGY://HKEY_LOCAL_MACHINE\SOFTWARE\My
Key")
'Displaying the ACE in the DACL --- it's the same you way you display aces
for File, FileShare, Registry, Exchange, and Active Directory's ACL.
Set dacl = sd.DiscretionaryAcl
Debug.Print Date & Time & "Initial Values of DACL"
For Each ace In dacl
Debug.Print ace.Trustee
Debug.Print Hex(ace.AccessMask)
Debug.Print Hex(ace.AceType)
Debug.Print Hex(ace.AceFlags)
Debug.Print Hex(ace.Flags)
Next
Debug.Print dacl.AceCount
'
' Initialize all of the new ACLs
'
Set newAce = CreateObject("AccessControlEntry")
Set newdacl = CreateObject("AccessControlList")
Set ImpDenyDacl = CreateObject("AccessControlList")
Set InhDenyDacl = CreateObject("AccessControlList")
Set ImpAllowDacl = CreateObject("AccessControlList")
Set InhAllowDacl = CreateObject("AccessControlList")
newAce.Trustee = "Redmond\maxv"
newAce.AccessMask = ADS_RIGHTS_RGY_KEY_READ
newAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED
newAce.AceFlags = ADS_ACEFLAG_INHERIT_ACE
ImpAllowDacl.AddAce newAce
For Each ace In dacl
'
' Sort the orignal ACEs into thier appropriate
' ACLs
'
Debug.Print ace.Trustee
If ((ace.AceFlags And ADS_ACEFLAG_INHERITED_ACE) =
ADS_ACEFLAG_INHERITED_ACE) Then
'
' We have an inheritted ace, deterimine if it
' is an Allow or Deny ACE
'
Select Case ace.AceType
Case ADS_ACETYPE_ACCESS_ALLOWED
'
' We have an inherited allow ace, add it to the
' InhAllowDacl
'
InhAllowDacl.AddAce ace
Case Else
'
' We have an inheritted Deny ace
'
InhDenyDacl.AddAce ace
End Select
Else
'
' We have an implicit Ace
'
Select Case ace.AceType
Case ADS_ACETYPE_ACCESS_ALLOWED
'
' We have an implicit allow ace
'
ImpAllowDacl.AddAce ace
Case Else
'
' We have an Implicit Deny Ace
'
ImpDenyDacl.AddAce ace
End Select
End If
Next
'
' Combine the ACEs in the proper order
' Implicit Deny
' Implicit Allow
' Inherit Deny
' Inherit Allow
'
' Implicit Deny
'
For Each ace In ImpDenyDacl
newdacl.AddAce ace
Next
'
' Implicit Allow
'
For Each ace In ImpAllowDacl
newdacl.AddAce ace
Next
'
' Inherit Deny
'
For Each ace In InhDenyDacl
newdacl.AddAce ace
Next
'
' Inherit Allow
'
For Each ace In InhAllowDacl
newdacl.AddAce ace
Next
sd.DiscretionaryAcl = newdacl
Debug.Print Date
For Each ace In newdacl
Debug.Print ace.Trustee
Debug.Print "Ace Mask: " & Hex(ace.AccessMask)
Debug.Print "Ace Type: " & Hex(ace.AceType)
Debug.Print "Ace Flags: " & Hex(ace.AceFlags)
Debug.Print "Object Type value: " & Hex(ace.Flags)
Next
'
' Set the appropriate revision level
' for the DACL
'
newdacl.AclRevision = dacl.AclRevision
'
' Replace the Security Discriptor
'
sec.SetSecurityDescriptor sd
'
' Now, we need to force inheritance to propagate...
'
PropagateInheritance "MACHINE\SOFTWARE\My Key"
End Sub
Sub PropagateInheritance(key As String)
'
' See the following link for details on the format of the registry
' key string:
'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/S
ecurity/se_object_type.asp
'
Dim dwRet As Long
Dim PSID As Long
Dim psidGroup As Long
Dim pDacl As Long
Dim pSacl As Long
Dim secInfo As Long: secInfo = DACL_SECURITY_INFORMATION
dwRet = GetNamedSecurityInfoA(key, SE_REGISTRY_KEY, secInfo, _
0, 0, pDacl, 0, 0)
If (dwRet = 0) Then
'
' The API returned successfully, so we can set the
' Dacl back onto the key
'
dwRet = SetNamedSecurityInfoA(key, SE_REGISTRY_KEY, secInfo, _
0, 0, pDacl, 0)
'
' Time to release the pDacl pointer...must call the LocalFree API
'
LocalFree pDacl
Else
'
' Bummer, we have an error!
'
Dim errVal As Long: errVal = GetLastError()
Err.Raise dwRet, "PropagatInheritance", "GetNamedSecurityInfo Returned an
error"
'Err.Number = GetLastError()
'Err.Description = "GetNamedSecurityInfo Error" & vbCrLf
End If
End Sub
"Dude, you so totally rocked!"
- Finding Nemo
Regards,