Getting elevated privileges on demand using C#

With going on stage Windows Vista and Windows 7 later on and new user security paradigm introduction (UAC), it becomes necessary to support such behavior when elevated privileges are required to perform some portion of code base, i.e. writing to registry, modifying files under system protected folders, etc.

So, in general, there are two ways to implement such behavior:

Embed a manifest info executable to indicate that the application requires elevated privileges from the beginning and can’t be run without gaining administrative rights at all. Here’s an example of such manifest:
Separate the code base into two parts: the first doesn’t require elevated privileges and the second – does, so call one from another. The article covers a case when the calling application is a console with a number of command line arguments: some of them can be run in normal mode and some – only with administrative rights.

Usually the part of the program requires elevated privileges is a settings form which writes to Windows registry when the core functionality – don’t.

Another case – a console application where core functionality requires elevated privileges and some helpers – such as help message displaying – don’t.

Let’s declare the skeleton of such console application.

Entry point method parses input command line arguments and branches the flow control relying on the parse results wrapped into a object:

static void Main(string[] args){ // wrap command line arguments to an object Core.Settings = ApplicationSettingsParser.Parse(args); if (Core.Settings.UsageFlag || (args.Length == 0)) { // run without elevated privileges PrintUsage(); } else if (!Core.Settings.EngageFlag) { // runs with the same arguments plus flag mentioning the main action performing var info = new ProcessStartInfo( Assembly.GetEntryAssembly().Location, String.Join(” “, Enumerable.Concat(args, new[] { “–engage” }))) { Verb = “runas”, // indicates to eleavate privileges }; var process = new Process { EnableRaisingEvents = true, // enable WaitForExit() StartInfo = info }; process.Start(); process.WaitForExit(); // sleep calling process thread until evoked process exit } else if (Core.Settings.EngageFlag) { // do stuff under elevated privilegesConsole.WriteLine(“Elevated privileges gained={0}”, Core.IsElevated); }}

Here’s a method just displaying a sample help message:

private static void PrintUsage(){ Console.WriteLine(“Usage: ElevatedPrivilegesOnDemand.exe –do [--engage] | -?”);}

Parsing method is placed into a dedicated helper:

public static ApplicationSettings Parse(string[] args){ var settings = new ApplicationSettings(); for (int i = 0; i < args.Length; i++) { var param = args[i]; switch (param) { case "-?": { // stop further parsing and return only meaning flag return new ApplicationSettings() { UsageFlag = true }; } case "--do": { settings.DoFlag = true; break; } case "--engage": { settings.EngageFlag = true; break; } } } return settings;}

Which returns a POCO object keeping settings:

class ApplicationSettings{ public ApplicationSettings() { // default settings setup } public bool DoFlag { get; set; } public bool EngageFlag { get; set; } public bool UsageFlag { get; set; }}

Internal singleton setting instance is attached to a pivot class. It also contains an addition helper method to check elevated privileges obtaining:

static class Core{public static bool IsElevated{get{return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);}}public static ApplicationSettings Settings { get; set; }}

The executing flow is being separated to the two parts: in the first it’s being determined whenever elevated privileges are required relying on command line arguments specified or not. And if yes – an additional parameter is being added and passed to the same application but started with administrative rights and redirected  console output.
And in the second, the core functionality is being executed with full privileges gained.

Now there is no needs to run the whole application under elevated privileges mode when it is not necessary.

Unfortunately it seems that it’s not possible to hide child process window and elevate its privileges in the same time:

ProcessStartInfo.Verb will only have an effect if the process is started by ShellExecuteEx() which requires UseShellExecute = true Redirecting I/O and hiding the window can only work if the process is started by CreateProcess() which requires UseShellExecute

I’m investigating this behavior and will update my article as far will find a solution to hide a window of started elevated process. 

Reader can find next links to be interesting: 

Questions tagged UAC and manifest on Stack Overflow, especially this and related. 

28/08/2010 – version 1.0.1 – Initial release.  

29/08/2010 – version 1.0.2 – Fix of example source code.

30/08/2010 – version 1.1.3 – Code change and remark addition considering hiding window of process started with elevated previliges.







View the original article here