UnauthorizedAccessException when creating second NamedPipeServerStream in a process with a PipeSecurity argument

22 Views Asked by At

In a project, I am using the fantastic Named Pipes library: https://github.com/IfatChitin/Named-Pipes

It is solid and works like a charm for projects running under the same security context. However, if I want to have pipes go across security contexts, it is failing me.

The current implementation of the library does not use any specific security contexts, so it uses some default where connections are only allowed in the same security context. The library uses a pool of NamedPipeServerStream objects to manage multiple connections and at the core of the library, in the class InternalPipeServer is the constructor:

public InternalPipeServer(string pipeName, int maxNumberOfServerInstances)
{
    _pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumberOfServerInstances,
        PipeTransmissionMode.Message, PipeOptions.Asynchronous);
    Id = Guid.NewGuid().ToString();
}

You can see it uses the constructor without a security context (no PipeSecurity) object.

I have tried different solutions. I tried modifying the PipeSecurity object it is created with by something like:

_pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumberOfServerInstances,
    PipeTransmissionMode.Message, PipeOptions.Asynchronous);

var acl = _pipeServer.GetAccessControl();
// ... do stuff to ACL
_pipeServer.SetAccessControl(acl);

But, it throws exceptions... and it does appear as if it is impossible to change the security on an open pipe. That does make sense to me in a way. So, the next step was to specify my own PipeSecurity object on creation. That worked...however, only for the first NamedPipeServerStream. After the first one is created, I can connect cross security contexts (because the security I specified is World--to start with in my testing), however, the library manages a pool of these things and when a connection occurs, then it creates another NamedPipeServerStream. The stock library handles it all fine, however, when my hacked version tries it, it fails on creating the second NamedPipeServerStream.

My final hacked version gives an UnauthorizedAccessException. I would like to figure out how to set the security correctly so in the library, it can create multiple NamedPipeServerStream for its pool of pipes.

Snippet of hacked version:

static PipeSecurity PipeSecurity { get; set; }

#region c'tor

/// <summary>
/// Creates a new NamedPipeServerStream 
/// </summary>
public InternalPipeServer(string pipeName, int maxNumberOfServerInstances)
{
    if (PipeSecurity == null)
    {
        var pipeSecurity = new PipeSecurity();
        var sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
        var rule = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
        pipeSecurity.AddAccessRule(rule);
        PipeSecurity = pipeSecurity;
    }

    _pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumberOfServerInstances,
        PipeTransmissionMode.Message, PipeOptions.Asynchronous, 0, 0, PipeSecurity);
    Id = Guid.NewGuid().ToString();
}

#endregion

Exception:

System.UnauthorizedAccessException
  HResult=0x80070005
  Message=Access to the path is denied.
  Source=System.Core
  StackTrace:
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.Pipes.NamedPipeServerStream.Create(String fullPipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeAccessRights rights, SECURITY_ATTRIBUTES secAttrs)
   at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)
   at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity)
   at ClientServerUsingNamedPipes.Server.InternalPipeServer..ctor(String pipeName, Int32 maxNumberOfServerInstances) in C:\src\downloads\Named-Pipes\ClientServerUsingNamedPipes\ClientServerUsingNamedPipes\Server\InternalPipeServer.cs:line 51
   at ClientServerUsingNamedPipes.Server.PipeServer.StartNamedPipeServer() in C:\src\downloads\Named-Pipes\ClientServerUsingNamedPipes\ClientServerUsingNamedPipes\Server\PipeServer.cs:line 82
   at ClientServerUsingNamedPipes.Server.PipeServer.ClientConnectedHandler(Object sender, ClientConnectedEventArgs eventArgs) in C:\src\downloads\Named-Pipes\ClientServerUsingNamedPipes\ClientServerUsingNamedPipes\Server\PipeServer.cs:line 151
   at ClientServerUsingNamedPipes.Server.InternalPipeServer.OnConnected() in C:\src\downloads\Named-Pipes\ClientServerUsingNamedPipes\ClientServerUsingNamedPipes\Server\InternalPipeServer.cs:line 240
   at ClientServerUsingNamedPipes.Server.InternalPipeServer.WaitForConnectionCallBack(IAsyncResult result) in C:\src\downloads\Named-Pipes\ClientServerUsingNamedPipes\ClientServerUsingNamedPipes\Server\InternalPipeServer.cs:line 165
   at System.IO.Pipes.NamedPipeServerStream.AsyncWaitForConnectionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

  This exception was originally thrown at this call stack:
    [External Code]
    ClientServerUsingNamedPipes.Server.InternalPipeServer.InternalPipeServer(string, int) in InternalPipeServer.cs
    ClientServerUsingNamedPipes.Server.PipeServer.StartNamedPipeServer() in PipeServer.cs
    ClientServerUsingNamedPipes.Server.PipeServer.ClientConnectedHandler(object, ClientServerUsingNamedPipes.Interfaces.ClientConnectedEventArgs) in PipeServer.cs
    ClientServerUsingNamedPipes.Server.InternalPipeServer.OnConnected() in InternalPipeServer.cs
    ClientServerUsingNamedPipes.Server.InternalPipeServer.WaitForConnectionCallBack(System.IAsyncResult) in InternalPipeServer.cs
    [External Code]
0

There are 0 best solutions below