Named Pipe Server throws UnauthorizedAccessException when creating a second instance if PipeSecurity is set
There are two things which can cause the instantiation of a second or subsequent NamedPipeServerStream on the same pipe to fail:
- the maxNumberOfServerInstances ctor argument must have been set to more than 1 when the first instance of the pipe server was created. If not, the second call will fail unless the first instance has already been closed completely.
- the process calling the ctor must have the access right represented by PipeAccessRights.CreateNewInstance. This is a powerful right which the pipe server should guard jealously, as it allows its possessor the ability to act as a pipe server.
The service process should set the pipe security thus:
PipeSecurity ps = new PipeSecurity();
ps.AddAccessRule(new PipeAccessRule(myPipeUsersGroup, PipeAccessRights.ReadWrite, AccessControlType.Allow));
ps.AddAccessRule(new PipeAccessRule(myPipeServerIdentity, PipeAccessRights.FullControl, AccessControlType.Allow));
where:
myPipeUsersGroup
is a placeholder for a group which contains all the prospective client identities which will connect to the pipe. Depending on your requirements/use case this might be a specific client identity, a custom group, or a built in group such as "Users" or "Administrators".myPipeServerIdentity
is a placeholder for the service identity. This might be set, for example, toWindowsIdentity.GetCurrent().Owner
. When the pipe server is hosted in a Windows service, then even better (but a good deal harder to implement) would be the Logon SID identity of the service process - this would ensure that only the specific service process could create instances of the pipe.
If you want to ensure that pipe access is restricted to just users logged on locally i.e. to prevent remote access across a network, you can also add a deny ACE for Network Users into the pipe security ACL.
I figured it out.
static void Main()
{
PipeSecurity ps = new PipeSecurity();
ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow));
ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
ps.AddAccessRule(pa);
using (NamedPipeServerStream pipeServer =
new NamedPipeServerStream("testpipe",PipeDirection.InOut,10,
PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024,1024,ps))
using (NamedPipeServerStream pipeServer2 =
new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10,
PipeTransmissionMode.Message, PipeOptions.WriteThrough,1024,1024,ps))
{
By adding the rights PipeAccessRights.CreateNewInstance
it now works fine.
I hit another snag but i solved it, but wanted to post it in case other people found this through Google. by providing your own Pipe security object it removes the default one, so if you need it you need to re-add the System group so it can talk to the pipe if you are writing a service. I updated my above code to what I used to get a elevated service and a non elevated winforms app to talk to each other (Creator owner is likely unnecessary)
The solution that works on localized versions of Windows:
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
accessRights, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.CreatorOwnerSid, null),
PipeAccessRights.FullControl, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
PipeAccessRights.FullControl, AccessControlType.Allow));