Subscribe: this.Pose() as Expert - WCF
Preview: this.Pose() as Expert - WCF

this.Pose() as Expert - WCF

Last Build Date: Sun, 04 Feb 2007 21:23:45 GMT

Copyright: Christoph Wille

UAC Elevation in Managed Code: "Talking" to an Elevated Process via WCF

Sun, 04 Feb 2007 21:23:45 GMT

In the blog post UAC Elevation in Managed Code: Starting Elevated Processes I talked about how to start an elevated process. However, just starting a process might not cut the mustard, for example if you need to hand over data to the elevated process. You could achieve this by passing, let's say, some data as command line arguments to ProcessInfo before starting the elevated process. But that seriously limits communication. So how can you perform communication with an elevated process? My first idea was to use .NET Remoting. Once I thought through the multi-instance scenario, I quickly realized that this meant the server had to be running in the non-elevated application, because only it could properly choose a port. And because I am not a fan of Remoting anyways, I decided to give WCF (Windows Communication Foundation, a pillar of .NET 3.0) a try. It looked like smooth sailing at first, but then I realized that with WCF too I needed to implement the service inside the non-elevated application. This time, however, the reason was "How do I know when the elevated application has initialized before I can actually start communicating with it?". Back to the drawing board. The final solution now looks like this: the non-elevated application starts a service. The operations contract specifies a callback, which, once the elevated application has signalled its readiness, can be used by the non-elevated application to "talk" with the elevated application. I didn't intend to go duplex, but hey, if there's no other way I am willing to take plunge. Speaking of tricks of the trade: I am using imperative binding to a named pipe. Reason? Well, WS bindings won't work (see here and here), and the TCP channel would pop up a firewall warning. That's why. Let's look at the applications - first the non-elevated one: This time I forfeited eye candy (the shield button). Same (missing eye candy) goes for the elevated application as it is a console application only: Solution-wise, this simple two-application scenario is split into four projects: So where do we start? With the easy part inside ElevationContract: [ServiceContract(Namespace = "http://Christoph.Wille.Samples", CallbackContract = typeof(IElevatedProcess))] public interface IWaitForElevatedProcess {   [OperationContract(IsOneWay = false)]   void ElevatedProcessStarted(); } [ServiceContract(Namespace = "http://Christoph.Wille.Samples")] public interface IElevatedProcess {   [OperationContract(IsOneWay = false)]   void SayHello(string message); } The interface IWaitForElevatedProcess is implemented in StandardUserApp. It is the service endpoint that is initialized before the elevated process is started - and once the elevated application is up and running, it calls into ElevatedProcessStarted. And we are in business for using the IElevatedProcess callback that is implemented in the ElevatedProcess console application. So how is the service endpoint intialized - let's take a look inside: private const string theProcess = @"..\..\..\ElevatedProcess\bin\Debug\ElevatedProcess.exe"; private void tryitButton_Click(object sender, EventArgs e) {   string channelIdentifier = MiscHelpers.CreateRandomString(64);   MyUACServiceHost.StartService(channelIdentifier);   // starting it modal doesn't work (obviously - unless we have more threads, of course)   ElevatedProcess.Start(theProcess, channelIdentifier); } Interesting tidbit #1 is CreateRandomString: it creates a random string to use for the address. Why? Well, if multiple instances of our application are running and trying to elevate a process, we are in trouble. Which brings me to StartService: internal static void StartService(string pipeEndPoint) {   NetNamedPipeBinding binding = new NetNamedPipeBinding();   binding.Name = "uacbinding";   binding.Security.Mode = NetNamedPipeSecurityMode.Transport;   Uri baseAddress = new Uri("net.pipe://localhost/uac/" + pipeEndPoint);   myServiceHost = new ServiceHost(typeof(SampleService), baseAddress); [...]

Security Brief: Why won't my simple WCF service start when I run it as a non-administrator?

Sun, 12 Nov 2006 15:41:26 GMT

This Q&A item is part of the current MSDN magazine's Security Brief's column by Keith Brown. I am pretty sure that this problem will rear its head sooner or later on every developers machine, that's why I am 'pinning' the link in my blog for my own reference too.