Link to home
Start Free TrialLog in
Avatar of Daniel Wilson
Daniel WilsonFlag for United States of America

asked on

Win API in VB6 -- What is a Struct_MembersOf_PACL ?

The richer translations of the SetSecurityInfo declaration into VB include a Struct_MembersOf_PACL as one of the types.
'http://binaryworld.net/Main/ApiDetail.aspx?ApiId=4821
Declare Function SetSecurityInfo Lib "ADVAPI32" (ByVaL handle As Long, ByRef ObjectType As SE_OBJECT_TYPE, ByVaL SecurityInfo As Long, ByRef psidOwner As SID, ByRef psidGroup As SID, ByVaL pDacl As Struct_MembersOf_PACL, ByVaL pSacl As Struct_MembersOf_PACL) As Long
       
What is the thing?

I have the ACL structure:
'http://msdn.microsoft.com/en-us/library/aa374931(VS.85).aspx
Private Type ACL
    AclRevision As Byte
    Sbz1 As Byte
    AclSize As Integer
    AceCount As Integer
    Sbz2 As Integer
End Type

Is that what I need?  Or is a Struct_MembersOf_PACL something else?

Thanks!
Avatar of jkr
jkr
Flag of Germany image

That is a pointer to a DACL, see http://msdn.microsoft.com/en-us/library/aa379588(VS.85).aspx ("SetSecurityInfo Function"). However, a DACL has no "members", it is a more or less "opaque" thing. Check out http://msdn.microsoft.com/en-us/library/ms717798(VS.85).aspx ("Creating a DACL") which shows a less cumbersome way to build one using 'ConvertStringSecurityDescriptorToSecurityDescriptor()' (http://msdn.microsoft.com/en-us/library/aa376401.aspx)
Avatar of Daniel Wilson

ASKER

Right, it's a pointer.  And VB6 obfuscates pointers severely.

Would you use the translation that sees pDacl and pSacl as Long then?

Thanks!
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Looks like you're right.  I hit upon something more complex (and evidently wrong) as an attempt at solving this one:
https://www.experts-exchange.com/questions/24330006/SetSecurityInfo-returns-error-1336-ERROR-INVALID-ACL.html

Thanks for steering me away from one non-solution!
I even get error 1336 when passing a NULL DACL ...

lErrorCheck = SetSecurityInfo(MyHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, _
                                0, 0, 0, 0)
Hmmm, what kind of object are you trying to apply the ACL to?
The current process.

Simplified, it is:

MyPID = GetCurrentProcessID()
OpenProcess(ACCESS_RIGHT_READ_CONTROL Or ACCESS_RIGHT_WRITE_DAC, 0, MyPID)
GetSecurityInfo(MyHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, pCurDacl, 0, pSD)
SetEntriesInAcl(1, ea, pCurDacl, pNewDacl)
SetSecurityInfo(MyHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, pNewDacl, 0)
First of all, try PROCESS_ALL_ACCESS as the access mask. Also, does 'SetEntriesInAcl()' succed?
Yes, SetEntriesInAcl returns 0 ... which I understand to mean Success.

like I have below?  Currently I'm using PROCESS_QUERY_INFORMATION

Dim ea As EXPLICIT_ACCESS
1090        With ea
1100            .grfAccessPermissions = PROCESS_ALL_ACCESS
1110            .grfAccessMode = GRANT_ACCESS
1120            .grfInheritance = NO_INHERITANCE
1130            .TRUSTEE.TrusteeForm = TRUSTEE_IS_NAME
1140            .TRUSTEE.TrusteeType = TRUSTEE_IS_GROUP
'1150            .TRUSTEE.ptstrName = "CURRENT_USER" & vbNullChar 'Perhaps this should actually have the current Windows user name ... not sure
1150            .TRUSTEE.ptstrName = "EVERYONE" '& vbNullChar
1160        End With

Open in new window

http://msdn.microsoft.com/en-us/library/ms684880.aspx doesn't say what the constant PROCESS_ALL_ACCESS equals.  I'm going to assume it equals &HFFFF.
Hm, I've never set en EXPLICITACCESS struct manually (or seen that) - have you tried doing that with 'BuildExplicitAccessWithName()' (http://msdn.microsoft.com/en-us/library/aa376378(VS.85).aspx)? See also http://support.microsoft.com/kb/295004 ("How to use high-level access control APIs from Visual Basic")
Nice idea ... same error 1336 ERROR_INVALID_ACL

Code now looks like:

(I'm using &HFFFF as PROCESS_ALL_ACCESS.)

further ideas?


MyPID = GetCurrentProcessID()
OpenProcess(ACCESS_RIGHT_READ_CONTROL Or ACCESS_RIGHT_WRITE_DAC, 0, MyPID)
Call BuildExplicitAccessWithName(ea, "EVERYONE", ACCESS_RIGHT_PROCESS_ALL_ACCESS, GRANT_ACCESS, 0)
GetSecurityInfo(MyHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, pCurDacl, 0, pSD)
SetEntriesInAcl(1, ea, pCurDacl, pNewDacl)
SetSecurityInfo(MyHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, pNewDacl, 0)

Open in new window

Aaah, just spotted a subtle difference - 'SetEntriesInAcl()' is declared as follows:

DWORD SetEntriesInAcl(
  ULONG cCountOfExplicitEntries,
                 // number of entries in the list
  PEXPLICIT_ACCESS pListOfExplicitEntries,
                 // pointer to list of entries with new access data
  PACL OldAcl,   // pointer to the original ACL
  PACL *NewAcl   // receives a pointer to the new ACL
);

with the last argument being 'PACL *NewAcl' - which is a pointer to a pointer (or the address of a pointer). Dunno VB, so let me just ask a stupid question: Are you taking this into account?
That's probably the worst thing about VB -- the obfuscation of pointers.

Let me try VarPtr(pNewDacl).  I think that would be the right answer there.

The other thing in that declaration that has me worried is the 2nd argument.  I have an Explicit_Access, not a list of them.
The address of one element will do - if the 1st arg is '1'.
VarPtr(pNewDacl) is wrong.  It results in pNewDacl remaining = 0.

The truth is, just passing a Long (which is a pointer to something)  by reference (that is, using a pointer to it) is giving us the double indirection.


Private Declare Function SetEntriesInAcl Lib "Advapi32.dll" Alias "SetEntriesInAclA" (ByVal cCountOfExplicitEntries As Long, pListOfExplicitEntries As EXPLICIT_ACCESS, ByVal OldAcl As Long, ByRef NewAcl As Long) As Long

I'm still not sure about PEXPLICIT_ACCESS.

I'm attaching a watch list from the last run without the VarPtr() ...

SetSecurityInfo-WatchList.gif
>>The address of one element will do - if the 1st arg is '1'.

OK, that's cool.  Then we're fine as that's also a ByRef parameter.
(In VB6 parameters are ByRef unless specified ByVal.  MS switched this in .Net.)
Have you checked http://support.microsoft.com/kb/295004 ("How to use high-level access control APIs from Visual Basic") from above - it comes with sample code.
Their example works.  They are using GetNamedSecurityInfo and SetNamedSecurityInfo.

I'll try tweaking  their code until it does what I want.  

Thanks for the help so far!  

What we're actually working on now is this question that's been out there for a day.
https://www.experts-exchange.com/questions/24330006/SetSecurityInfo-returns-error-1336-ERROR-INVALID-ACL.html

So if we get a solution, please post it there as you will have earned the points!
I can't use GetNamedSecurityInfo and SetNamedSecurityInfo.
http://msdn.microsoft.com/en-us/library/aa379593(VS.85).aspx
"The  GetSecurityInfo and  SetSecurityInfo functions support all types of kernel objects. The  GetNamedSecurityInfo and  SetNamedSecurityInfo functions work only with the following kernel objects: semaphore, event, mutex, waitable timer, and file mapping."

I'll have to pick this up again when my mind is fresher.

Again, thanks for the help!