Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# UnauthorizedAccessException when enabling MessageMode for read-only named pipe (NamedPipeClientStream class)

There's a problem with the NamedPipeClientStream class in .NET, in that you cannot create an instance of this class with PipeDirection.In, and then successfully change the ReadMode to PipeTransmissionMode.Message.

Attempting to do so will raise an UnauthorizedAccessException. Although pipes would usually be used to communicate between processes, this simple example within a single process shows the problem:

var pipeOut = new NamedPipeServerStream("SomeNamedPipe", 
                                        PipeDirection.Out, 
                                        1, 
                                        PipeTransmissionMode.Message);
var pipeIn = new NamedPipeClientStream(".", 
                                       "SomeNamedPipe", 
                                       PipeDirection.In);
pipeIn.Connect();
pipeIn.ReadMode = PipeTransmissionMode.Message;

This code will throw an UnauthorizedAccessException when attempting to set the ReadMode Property.


In a search for information on this problem, I found references to it in other places, such as here:

  • Named pipes issue: System.UnauthorizedAccessException: Access to the path is denied.

  • WPF - Messaging using Windows Pipes protocol

  • PipeTransmissionMode.Message: How do .NET named pipes distinguish between messages?

All of these posts mention that this is "weird", "odd", etc, but don't explain "why" it doesn't work, and all give the same workaround, that "for some strange reason" setting the pipe direction to InOut makes it work.

It's true that this does make it work, but it requires fundamentally changing the definition of the pipe, on both ends, to full duplex rather than going in a single direction, which I consider to be a very poor approach, and unless you're able to change both the client and the server, this may not even be possible.


My question was, why does enabling message mode on an inbound pipe cause an exception, and is there a better way to address this issue than changing the pipe to bi-directional mode?

like image 431
Roger Sanders Avatar asked Sep 23 '15 12:09

Roger Sanders


People also ask

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What is C programming used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Why is C named so?

Quote from wikipedia: "A successor to the programming language B, C was originally developed at Bell Labs by Dennis Ritchie between 1972 and 1973 to construct utilities running on Unix." The creators want that everyone "see" his language. So he named it "C".

What is C of computer?

C is a high-level and general-purpose programming language that is ideal for developing firmware or portable applications. Originally intended for writing system software, C was developed at Bell Labs by Dennis Ritchie for the Unix Operating System in the early 1970s.


1 Answers

Looking at the Microsoft reference source, I could see that setting the ReadMode property simply calls the win32 SetNamedPipeHandleState function to perform the operation, with errors from this call raised as exceptions. As per the documentation SetNamedPipeHandleState function it states about the pipe handle that in order to call this function

the handle must have GENERIC_WRITE access to the named pipe for a write-only or read/write pipe, or it must have GENERIC_READ and FILE_WRITE_ATTRIBUTES access for a read-only pipe.

Herein lies the problem.

If we look at the constructors for NamedPipeClientStream that take in a PipeDirection setting, we see that they only request GENERIC_READ access for PipeDirection.In, and GENERIC_WRITE access for PipeDirection.Out (or both for InOut). This means that any pipe opened in Out or InOut mode will work, as GENERIC_WRITE access is sufficient for those cases, but we need both GENERIC_READ and FILE_WRITE_ATTRIBUTES for a read-only pipe, which the NamedPipeClientStream class never requests. This is a defect in the class, and should be corrected by Microsoft.

I've submitted a bug report on Microsoft Connect here:

https://connect.microsoft.com/VisualStudio/feedback/details/1825187

Please up-vote it if you come across this problem yourself, it might help speed up a fix.


Until a fix (none as of 3/2017), one can work around this problem entirely by using a different constructor for NamedPipeClientStream.

There's one overload of the constructor that takes in, instead of a PipeDirection enumeration, a PipeAccessRights enumeration instead, where you can specify the particular combination of access rights you want to obtain for the handle. The constructor then derives the direction of the pipe from the combination of specified access rights (In if ReadData is specified, Out" if WriteData is specified, InOut if they are both specified).

This means, you can solve this problem without having to make your pipes full duplex, by simply changing a constructor line like this:

var pipeIn = new NamedPipeClientStream("<ServerName>", "<PipeName>", PipeDirection.In);

to this:

var pipeIn = 
   new NamedPipeClientStream("<ServerName>", 
                             "<PipeName>", 
                             PipeAccessRights.ReadData | PipeAccessRights.WriteAttributes, 
                             PipeOptions.None, 
                             System.Security.Principal.TokenImpersonationLevel.None, 
                             System.IO.HandleInheritability.None);

If you use this alternate constructor as a suggested workaround, the result will be identical and indistinguishable from the result you would get from the first form of the constructor, with the exception that this additional access right will be obtained, so that message mode can be enabled.

like image 88
Roger Sanders Avatar answered Sep 29 '22 08:09

Roger Sanders