问题
I have an Internet Explorer add-in, written in C#, which talks via a WCF named-pipe to a .NET desktop application. The desktop app creates the ServiceHost for the netNamedPipeBinding, and each instance of the IE add-in creates a ChannelFactory to talk to the app. Everything works fine under Windows XP, but an exception is thrown under IE's protected mode in Windows 7.
System.ServiceModel.CommunicationException: Cannot connect to endpoint 'net.pipe://localhost/MyApp.MyID'. ---> System.IO.PipeException: A pipe endpoint exists for '\.\pipe...guid...', but the connect failed: Access is denied. (5, 0x5)
Running the add-in under protected mode is a scenario I must support. My understanding is that if I lower the integrity level of the named-pipe, then my IE add-in will be allowed to talk through it. My question is how to do that. I have things setup to use WCF, and would preferably like to keep it that way. Can I make WCF create the named pipe with the lower integrity level? What code do I write to make that happen?
回答1:
I don't think this is going to be possible.
The problem is that the integrity label has to be specified in the security descriptor provided when the Named Pipe is created. In the standard NetNamedPipeBinding, that call to CreateNamedPipe
happens inside the private CreatePipe()
method of the internal WCF class System.ServiceModel.Channels.PipeConnectionListener
. I can't see a way to change how it specifies the initial security descriptor for the pipe.
See this question and answer for an outline of what we need to achieve.
Writing a custom named pipe transport binding element from scratch seems like the only way at present to get round this, failing which we'll just have to wait for Microsoft to add some enabling features in a future version of WCF. If you have access to Microsoft Connect, you could add your voice to the others requesting this feature.
EDIT: I was too pessimistic. I have now found a way to do this.
The key was that it turned out you don't necessarily have to specify the integrity label in the security descriptor when the pipe is created - but you do have to modify the SACL using the handle returned from CreateNamedPipe when the listener is opened - i.e. the very first server-side handle to the pipe. Using any other handle, the attempt to add the integrity label always fails, because the dwOpenMode
flag parameter to CreateNamedPipe
overloads the use of one of the bits to mean both FILE_FLAG_FIRST_PIPE_INSTANCE
and WRITE_OWNER
. We need the latter access permission in order to add the integrity label, but the presence of the former causes the call to fail on any but the first pipe instance.
Getting hold of the first pipe handle is not a trivial undertaking. WCF squirrels it away in an instance of the type System.ServiceModel.Channels.PipeConnectionListener.PendingAccept
, stored in a list maintained by the pipe connection listener. The connection listener is not the same thing as the channel listener (which can be grabbed straightforwardly by overriding the BuildChannelListener<>
method of a binding element), and it is much harder to get at. It involves heroics using reflection, to locate the TransportManager for the endpoint, which holds a reference to the endpoint's connection listener, and then working down a chain of connection listeners (which varies according to configuration of tracing etc) until the pipe connection listener is found. If we are lucky the first pipe handle can then be found in the listener's pending accept list (though there is a race condition here - if a client connects before we get hold of the handle, it will be gone forever).
Once the handle is available, lowering the integrity to allow low integrity clients to communicate wth the service is just a matter of calling SetSecurityInfo
on the handle to add the integrity label.
I plan to cover this is some detail on my blog soon.
来源:https://stackoverflow.com/questions/4064634/how-to-lower-integrity-of-wcf-named-pipe