Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the UAC implementation best practices? (.NET)

I'm thinking about developing an application that should run as standard user most of the time, but for certain operations, elevated administrative access will be required. The user expecience should be like in Windows Explorer when copying something into a protected folder.

Now the question is, how should this be implemented in .NET? I know that only entire processes or maybe some COM instances can be elevated, not single functions. But that would be exactly what I need. What path should I go? Write two executables, one with a manifest and the other without; programmatically run the same process elevated a second time; use some COM thing? Then I have the added privileges, but how to tell the other process what to do? Use .NET remoting (which is deprecated/complicated?); implement my own IPC thing using sockets/pipes/whatever? That elevated task may need to ask the user something in the middle of the process. And it must be cancellable.

There's a lot that tells me how UAC is working in the inside or how system administrators can configure it, but I haven't found anything that answers these basic questions.

like image 514
ygoe Avatar asked May 10 '11 08:05

ygoe


1 Answers

We appear to have 2 distinct questions here:

  1. How should I handle operations that require elevated privileges?
  2. If I use a separate process how should I tell the other process what to do?

Here's my attempt to answer them:

  1. It appears that from this SO Question: Windows 7 and Vista UAC - Programmatically requesting elevation in C# that the solution is as you suggested in your question (to run another process and have it request elevation on launch) is the 'right answer'
  2. As far as telling the other process what to do, here is how I would take a stab at it:

I would start by splitting out each of the actions that required elevated privileges to their own 'helper' programs. These helper programs would perform only a single action, taking arguments via the command line.

For example say your program needs to stop/start a service, I'd write a small helper program called servicecontroller (well in reality you'd probably want to use the net command) that took command line arguments similar to this:

servicecontroller stop MyCoolService
servicecontroller start MyCoolService

These arguments would be built up by the 'Main' program and passed along after hitting 'OK'.

There are several issues with the solution above though, that you may or may not care about:

  1. You are passing arguments on the command line, which can be easily sniffed
  2. You are limited by the length of the ProcessStartInfo.Argument + Program Path (from MSDN: The length of the arguments added to the length of the full path to the process must be less than 2080.)
  3. Getting information passed back to you might be a little tricky (should you need this)

A bit more googling revealed this blog post by 'DevZest' which basically recommends what I've described above. Good luck!


EDIT Based on the additional questions asked in the comments:

  1. Would you recommend starting a separate executable or the same executable when needing to perform elevated actions?
  2. (I'm reading between the lines on this one) How often should I prompt the user for these actions?

Without knowing exactly what you're doing here is my take on it:

  1. I would personally have separate executables for each of those actions, but not knowing exactly what you're trying to do its hard to make this call. In general though it seems like you'd want a separate process for each elevated action.
  2. I am a bit confused by your second example, once again without knowing exactly what you're attempting to do I'll just go based off the examples you gave in your comment.

In the file manager example I would do what explorer does and first spin though each of the destination directory to determine if any of the destination locations require elevated privileges to copy to. If they do I would mark a flag indicating that the action needs to be performed as an administrator, prompt the user and then perform the entire action as an administrator.

As to the text editor example, I would do something similar as above, when the user gives you a destination directory check to see that you have write access to that location, if not inform the user that they are saving to a location that requires elevation, save their work to a writable location (your program's APPDATA is probably a good place or even TEMP), then fire off the copy procedure which requests elevation, if the user cancels the UAC dialog make sure that you capture this cancel and delete the temporary file.

I would discourage you from keeping an elevated worker process around, if you find that your program needs to request elevation more than a few times (Readas: 1 or 2 corner cases) during the programs lifespan, then I would question why it wasn't marked as always elevated. I like to follow the rule of 'least surprise', when I gave you elevated rights I expect you to only perform the action that requested it, not to continue to pump actions that require elevation through the first request.

All of that being said there is nothing to prevent you from doing the above, once you let some process get elevated rights he can invite in all of his buddies. Based on your desire to keep an elevated process around why not just save the current state of the program, and relaunch the program with elevated privileges and restore the state? This, in my opinion, is the same as having the worker process exist in an always elevated state.

If you could tell us more about exactly what you're trying to do we might be able to find better ways to accomplish that, without having to run into UAC issues. While there are some very good reasons to write to areas protected by UAC, in most cases programs do not need to write/access to those locations.

like image 104
aolszowka Avatar answered Oct 15 '22 09:10

aolszowka