Hi,
That's part of it, but the key thing is that default permissions aren't enough - I need to provide a real security descriptor with explicit permissions in it.
Having played around with this for a while, I've got something that seems to work, so posting it here in case it helps anyone else. This thread was very useful in getting started:
viewtopic.php?f=12&t=54341&p=410919
It covers the process of initialising a security descriptor and dacl, although the dacl it creates is purposefully empty and I need to put things in it.
As I understand it, the way this works is:
- To create a named pipe with custom permissions, I have to provide a SECURITY_ATTRIBUTES structure.
- SECURITY_ATTRIBUTES contains a pointer to a SECURITY_DESCRIPTOR
- SECURITY_DESCRIPTOR contains a pointer to a DACL
- DACL is a kind of ACL
- ACL is a compound structure comprising an ACL header and then one or more ACEs which can be of various types.
- For what I want to do, an ACCESS_ALLOWED_ACE is the relevant type.
All the structure definitions seem to be known to PB out of the box. Likewise, most of the functions I need to call and the constants I need to use are also known by default - one exception was the CreateWellKnownSID call and a couple of the constants for that, which I was able to get from MS docs. This means we don't need to get too involved with how the ACL is structured.
Code: Select all
Prototype.i p_CreateWellKnownSID(sidtype.l,
*domainsid,
*psid,
cbsid.l)
Global.i lib_advapi32
Global CreateWellKnownSID.p_CreateWellKnownSID
; Constants we don't get for free
; From here: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-well_known_sid_type
#WinWorldSid=1
#WinLocalSystemSid=22
Procedure.i LoadADVAPI32()
Protected out.i, func$, func.i
out=#True
lib_advapi32=OpenLibrary(#PB_Any,"C:\Windows\System32\ADVAPI32.DLL")
If lib_advapi32
func$="CreateWellKnownSid"
func=GetFunction(lib_advapi32, func$)
If func
CreateWellKnownSID.p_CreateWellKnownSID=func
Else
Debug("failed to get function from advapi32 library: "+func$)
out=#False
EndIf
Else
Debug("Failed to open advapi32 library.")
out=#False
EndIf
ProcedureReturn out
EndProcedure
Procedure CreateMyNamedPipe()
Protected *sa.SECURITY_ATTRIBUTES
Protected *sd.SECURITY_DESCRIPTOR
Protected *dacl.ACL
Protected *sid
Protected.l rightsmask
Protected.l sidsize
Protected.i handle, result
; Create a security attributes structure
*sa=AllocateMemory(SizeOf(SECURITY_ATTRIBUTES))
; Set the length
*sa\nLength=SizeOf(SECURITY_ATTRIBUTES)
; Create a security descriptor
*sd=AllocateMemory(#SECURITY_DESCRIPTOR_MIN_LENGTH)
; Store the descriptor pointer on the sa structure
*sa\lpSecurityDescriptor=*sd
; Init the security descriptor
result=InitializeSecurityDescriptor_(*sd, #SECURITY_DESCRIPTOR_REVISION)
Debug("InitializeSecurityDescriptor result: "+Str(result))
; Create and init the dacl. Size unknown - 4096 is a guess and seems plenty
*dacl=AllocateMemory(4096)
result=InitializeAcl_(*dacl, 4096, #ACL_REVISION2)
Debug("InitializeACL result: "+Str(result))
; Permissions for System - all access.
*sid=AllocateMemory(4096)
sidsize=4096
; WinLocalSystemSid seems to be the same as NT AUTHORITY\SYSTEM
result=CreateWellKnownSID(#WinLocalSystemSid, #Null, *sid, @sidsize)
Debug("CreateWellKnownSID result: "+Str(result))
; the above call has updated sidsize with the size it actually used. Need to reset to use again below
sidsize=4096
; Add the permssion to the dacl
result=AddAccessAllowedAce_(*dacl, #ACL_REVISION2, #FILE_ALL_ACCESS, *sid)
Debug("AddAccessAllowedAce result: "+Str(result))
; Permissions for Everyone group.
; Rights mask needed for everyone access.
rightsmask=#FILE_LIST_DIRECTORY |
#FILE_READ_ATTRIBUTES |
#FILE_READ_DATA |
#FILE_READ_EA |
#SYNCHRONIZE |
#READ_CONTROL |
#FILE_WRITE_DATA |
#FILE_WRITE_ATTRIBUTES |
#FILE_WRITE_EA
FillMemory(*sid, 4096)
; WinWorldSid is Everyone group.
result=CreateWellKnownSID(#WinWorldSid, #Null, *sid, @sidsize)
Debug("CreateWellKnownSID result: "+Str(result))
result=AddAccessAllowedAce_(*dacl, #ACL_REVISION2, rightsmask, *sid)
Debug("AddAccessAllowedAce result: "+Str(result))
result=SetSecurityDescriptorDacl_(*sd, #True, *dacl, #False)
Debug("SetSecurityDescriptorDacl result: "+Str(result))
; Can now create the pipe
handle=CreateNamedPipe_("\\.\pipe\MyPipeName",
#PIPE_ACCESS_DUPLEX | #FILE_FLAG_FIRST_PIPE_INSTANCE,
#PIPE_TYPE_MESSAGE | #PIPE_READMODE_MESSAGE | #PIPE_REJECT_REMOTE_CLIENTS,
1,
65536,
65536,
0,
*sa)
; Can now free things
FreeMemory(*dacl)
FreeMemory(*sd)
FreeMemory(*sa)
; ... rest of code.
EndProcedure
CreateMyNamedPipe()
The above is hacked around a bit from the code I'm actually using, and doesn't do any real error detection (if anything goes wrong it carries on regardless). But I think it covers everything that needs doing.
The other key to solving this was the AccessChk utility from SysInternals (
https://docs.microsoft.com/en-us/sysint ... /accesschk). That allowed me to look at what the default permissions were on a named pipe. That let me see that SYSTEM was being given FILE_ALL_ACCESS, and the above permissions for Everyone are the default set plus the WRITE versions of all the READ permissions it already had.