From: mayayana on
Eduardo (or others who may be interested),

You posted code to list ACEs for an object
and I've begun looking at those options with
the idea in mind of writing a full-featured
class to encapsulate the horrendous
permissions API. But there seem to be gaps
and it's hard to figure out how the advapi
functions might fill them.

* It's fairly easy to set permissions.
* It's feasible to figure out whether the current
user is an Admin.
* You sample code shows how to return ACEs
for a specific object.

But what I don't find in the API is a basic
method to ask: What are the current user's
rights with this particular folder, Reg. key,
etc.? In other words, rather than listing ACEs
and returning a partial list of groups to match
up with those ACEs, it would be nice to just
"cut to the chase" and do it the other way around:
"What's "my" ACE for this object?"

If the CU is an Admin that could be a real
Admin or a limited Admin. (Having permission
to elevate is not the same as having permission.)
And I haven't found the method to return the
group status of the CU, other than whether or not
they're Admin.

Also, from my readings I
get the impression that Vista virtualization prevents
the accurate use of testing permissions by trying
to create a file in a folder or by trying to write to
HKLM. Virtualization will allow a fake version of
the operation without raising an error. So one
might write an all-users value to HKLM only to find
out later that it ended up in CU keys.



From: Eduardo on
mayayana escribi�:
> Eduardo (or others who may be interested),

So, you want to know the permissions of the CU for a particular object.
We'll have to investigate.

In the code posted we have:
1) Set permissions for "Users" and "Everyone".
2) Remove permissions for "Users" and "Everyone".

But we lack of a function to Get permissions for "Users" and "Everyone".

If we add that feature, I think we could also add Get/Set/Remove
permissions for CU.

If we want something even more complete, we could also add functions for
ACEs for denying access, because the functions that we have at this
time are for ACEs for allowing access.
From: mayayana on
I've been looking further and found
GetEffectiveRightsFromAcl. I'll play around
with that and see what I come up with.

> > Eduardo (or others who may be interested),
>
> So, you want to know the permissions of the CU for a particular object.
> We'll have to investigate.
>
> In the code posted we have:
> 1) Set permissions for "Users" and "Everyone".
> 2) Remove permissions for "Users" and "Everyone".
>
> But we lack of a function to Get permissions for "Users" and "Everyone".
>
> If we add that feature, I think we could also add Get/Set/Remove
> permissions for CU.
>
> If we want something even more complete, we could also add functions for
> ACEs for denying access, because the functions that we have at this
> time are for ACEs for allowing access.


From: Eduardo on
mayayana escribi�:
> I've been looking further and found
> GetEffectiveRightsFromAcl. I'll play around
> with that and see what I come up with.

OK, I could make this API work.
For running the sample, add a command button to the form and copy this code:

' ******** begin form's code ************

Option Explicit

Private Sub Command1_Click()
Dim iP As Long
Dim iPW As Boolean
Dim iFolder As String
Dim iMessage As String

iFolder = InputBox("Enter folder path", , _
"C:\Program Files\Internet Explorer")

If GetCurrentUserNTPermission(iFolder, 1, iPW, "Read") = 0 Then
iMessage = "Read permission: " & iPW & vbCrLf
End If
If GetCurrentUserNTPermission(iFolder, 1, iPW, "Write") = 0 Then
iMessage = iMessage & "Write permission: " & iPW & vbCrLf
End If
If GetCurrentUserNTPermission(iFolder, 1, iPW, "Execute") = 0 Then
iMessage = iMessage & "Execute permission: " & iPW & vbCrLf
End If
If GetCurrentUserNTPermission(iFolder, 1, iPW) = 0 Then
iMessage = iMessage & "All permissions: " & iPW
End If
If iMessage <> "" Then
MsgBox iMessage
Else
MsgBox "Error", vbExclamation
End If
End Sub


' ******** end form's code ************

' and in a module:

' ******** begin module's code ************

Option Explicit

Private Enum MULTIPLE_TRUSTEE_OPERATION
NO_MULTIPLE_TRUSTEE
TRUSTEE_IS_IMPERSONATE
End Enum

Private Enum TRUSTEE_FORM
TRUSTEE_IS_SID
TRUSTEE_IS_NAME
End Enum

Private Enum TRUSTEE_TYPE
TRUSTEE_IS_UNKNOWN
TRUSTEE_IS_USER
TRUSTEE_IS_GROUP
End Enum

Private Type TRUSTEE
pMultipleTrustee As Long
MultipleTrusteeOperation As MULTIPLE_TRUSTEE_OPERATION
TrusteeForm As TRUSTEE_FORM
TrusteeType As TRUSTEE_TYPE
ptstrName As String
End Type

Private Const SE_FILE_OBJECT = 1&
Private Const SE_REG_KEY = 4&
Private Const DACL_SECURITY_INFORMATION = 4&

Private Declare Function GetNamedSecurityInfo Lib "advapi32.dll" _
Alias "GetNamedSecurityInfoA" (ByVal ObjName As String, _
ByVal SE_OBJECT_TYPE As Long, ByVal SecInfo As Long, ByVal _
pSid As Long, ByVal pSidGroup As Long, pDacl As Long, ByVal _
pSacl As Long, pSecurityDescriptor As Long) As Long

Private Declare Function GetEffectiveRightsFromAcl Lib _
"advapi32.dll" Alias "GetEffectiveRightsFromAclA" (ByVal pacl _
As Long, pTrustee As TRUSTEE, ByRef pAccessRights As Long) As Long

Private Declare Function LocalFree Lib "KERNEL32" (ByVal hMem _
As Long) As Long

Private Type GENERIC_MAPPING
GenericRead As Long
GenericWrite As Long
GenericExecute As Long
GenericAll As Long
End Type

Private Declare Function MapGenericMask Lib "advapi32.dll" _
(ByRef grantedAccess As Long, ByRef pgenericmapping As _
GENERIC_MAPPING) As Long

Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const GENERIC_EXECUTE As Long = &H20000000
Private Const GENERIC_ALL As Long = &H10000000
'standard
Private Const DELETE = &H10000
Private Const READ_CONTROL = &H20000
Private Const WRITE_DAC = &H40000
Private Const WRITE_OWNER = &H80000
Private Const SYNCHRONIZE = &H100000
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const STANDARD_RIGHTS_READ = READ_CONTROL
Private Const STANDARD_RIGHTS_WRITE = READ_CONTROL
Private Const STANDARD_RIGHTS_EXECUTE = READ_CONTROL
Private Const STANDARD_RIGHTS_ALL = &H1F0000
Private Const SPECIFIC_RIGHTS_ALL = &HFFFF&
Private Const ACCESS_SYSTEM_SECURITY = &H1000000
Private Const MAXIMUM_ALLOWED = &H2000000
'specific
Private Const FILE_READ_DATA = &H1& ' file & pipe
Private Const FILE_LIST_DIRECTORY = &H1& ' directory
Private Const FILE_WRITE_DATA = &H2& ' file & pipe
Private Const FILE_ADD_FILE = &H2& ' directory
Private Const FILE_APPEND_DATA = &H4& ' file
Private Const FILE_ADD_SUBDIRECTORY = &H4& ' directory
Private Const FILE_CREATE_PIPE_INSTANCE = &H4& ' named pipe
Private Const FILE_READ_EA = &H8& ' file & directory
Private Const FILE_WRITE_EA = &H10& ' file & directory
Private Const FILE_EXECUTE = &H20& ' file
Private Const FILE_TRAVERSE = &H20& ' directory
Private Const FILE_DELETE_CHILD = &H40& ' directory
Private Const FILE_READ_ATTRIBUTES = &H80& ' all
Private Const FILE_WRITE_ATTRIBUTES = &H100& ' all

'generic rights masks for files and directories
Private Const FILE_ALL_ACCESS As Long = STANDARD_RIGHTS_REQUIRED _
Or SYNCHRONIZE Or 511
Private Const FILE_GENERIC_READ As Long = STANDARD_RIGHTS_READ _
Or FILE_READ_DATA Or FILE_READ_ATTRIBUTES Or _
FILE_READ_EA Or SYNCHRONIZE
Private Const FILE_GENERIC_WRITE As Long = STANDARD_RIGHTS_WRITE _
Or FILE_WRITE_DATA Or FILE_WRITE_ATTRIBUTES Or _
FILE_WRITE_EA Or FILE_APPEND_DATA Or SYNCHRONIZE
Private Const FILE_GENERIC_EXECUTE As Long = STANDARD_RIGHTS_EXECUTE _
Or FILE_READ_ATTRIBUTES Or FILE_EXECUTE Or SYNCHRONIZE

Private Function GetCUPermissions(ByVal nItem As String, nType _
As Long, nPermissions As Long) As Long
Dim iTrustee As TRUSTEE
Dim iObjType As Long
Dim iDACL As Long
Dim iDesc As Long
Dim iRet As Long

GetCUPermissions = -1
On Error GoTo woops

If (nType = 1) Then
iObjType = SE_FILE_OBJECT 'type 1
Else
iObjType = SE_REG_KEY 'type 4
End If

iRet = GetNamedSecurityInfo(nItem, iObjType, _
DACL_SECURITY_INFORMATION, 0&, 0&, iDACL, 0&, iDesc)

If iRet <> 0 Then GetCUPermissions = iRet: _
nType = 5: GoTo woops

iTrustee.pMultipleTrustee = 0
iTrustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE
iTrustee.TrusteeForm = TRUSTEE_IS_NAME
iTrustee.TrusteeType = TRUSTEE_IS_USER
iTrustee.ptstrName = "CURRENT_USER" & vbNullChar

iRet = GetEffectiveRightsFromAcl(iDACL, iTrustee, nPermissions)

If iRet <> 0 Then GetCUPermissions = iRet: _
nType = 6: GoTo woops

GetCUPermissions = 0
woops:
On Error Resume Next
If iDesc <> 0 Then LocalFree iDesc
End Function

Public Function GetCurrentUserNTPermission(ByVal nItem As String, _
nType As Long, nPermission As Boolean, Optional nDesiredAccess _
As String = "All") As Long

Dim iRet As Long
Dim iPermissions As Long
Dim iMap As GENERIC_MAPPING
Dim iGenericAccess As Long

Select Case UCase(nDesiredAccess)
Case "READ"
iGenericAccess = GENERIC_READ
Case "WRITE"
iGenericAccess = GENERIC_WRITE
Case "EXECUTE"
iGenericAccess = GENERIC_EXECUTE
Case "ALL"
iGenericAccess = GENERIC_ALL
Case Else
GetCurrentUserNTPermission = 7
End Select

If GetCurrentUserNTPermission = 0 Then
iRet = GetCUPermissions(nItem, nType, iPermissions)

If iRet <> 0 Then
GetCurrentUserNTPermission = 8
Else
GetCurrentUserNTPermission = 0

iMap.GenericRead = FILE_GENERIC_READ
iMap.GenericWrite = FILE_GENERIC_WRITE
iMap.GenericExecute = FILE_GENERIC_EXECUTE
iMap.GenericAll = FILE_ALL_ACCESS

MapGenericMask iGenericAccess, iMap
nPermission = (iPermissions And iGenericAccess) _
= iGenericAccess
End If
End If
End Function

' ******** end module's code ************
From: Eduardo on
Eduardo escribi�:
> mayayana escribi�:
>> I've been looking further and found
>> GetEffectiveRightsFromAcl. I'll play around
>> with that and see what I come up with.
>
> OK, I could make this API work.

But I'm not sure what it's returning when I check a virtualized folder,
because for "C:\Program Files\Internet Explorer" it tells me that I have
write rights, when in fact it's virtualized.

But unlike a "normal" folder, when I ask for all access rights, it tells
me that I don't have.

And it returns the same if I run it as admin or not.