windows-servicesnamed-pipes

'Access to the path is denied' when a NamedPipeClientStream tries to connect to a NamedPipeServerStream in a Windows service


We are implementing interprocess communications using Named Pipes. If I use a console application for both the NamedPipeClientStream and the NamedPipeServerStream it works beautifully. But when I move the server stream to a Windows service the client console application throws an UnauthorizedAccessException ('Access to the path is denied.') when the NamedPipedClientStream tries to connect.

The code to initialize both ends of the communication:

On the client console application:

  _clientStream = new NamedPipeClientStream(".", pipeName,
                                    PipeDirection.InOut, PipeOptions.None,
                                    TokenImpersonationLevel.Impersonation);

On the server Windows service:

 _server = new NamedPipeServerStream(pipeName, 
                                    PipeDirection.InOut, maxNumberOfServerInstances: 1);

EDIT: This seems to be a known problem up to at least Net 5. The problem is that you need extra security permissions server (Windows service) side that must be added to the constructor. But Net.Core and later do not provide such a constructor! Adding the permissions later by calling namedPipedServerStream.SetAccessControl does not seem to work. A Nuget package from a fellow developper supposedly solves it, but it seems incompatible with Net 8 for now. The solution: implement in Net Framework...

problem description

Nuget package to solve the problem


Solution

  • I solved it: You need the Nugetpackage: NamedPipeServerStream.NetFrameworkVersion Use it thus:

    using System.IO.Pipes;
    
    var pipeSecurity = new PipeSecurity();
    pipeSecurity.AddAccessRule(new PipeAccessRule(new 
        SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), 
        PipeAccessRights.ReadWrite, AccessControlType.Allow));
    
    using var serverStream = NamedPipeServerStreamConstructors.New(pipeName, 
        PipeDirection.InOut, 1, PipeTransmissionMode.Byte, 
        PipeOptions.Asynchronous | PipeOptions.WriteThrough, 0, 0, 
        pipeSecurity);