Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Getting Elevated Privileges on Demand using C#

0.00/5 (No votes)
9 Sep 2010 2  
The article reveals the details of how to execute only portion of application code base under elevated privileges

Introduction

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:
    <?xml version="1.0" encoding="utf-8" ?> 
    <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" 
    	xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" 
    	xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" 
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <assemblyIdentity version="1.0.0.0" name="MyApplication" />
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
            <security>
                <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                    <requestedExecutionLevel level="requireAdministrator" 
    		uiAccess="false" />
                </requestedPrivileges>
            </security>
        </trustInfo>
    </asmv1:assembly>  
  • 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.

Background

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.

The Code

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 an 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 elevate 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 privileges
	Console.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(IEnumerable<string> args)
{
    var settings = new ApplicationSettings();
    foreach (var arg in args)
    {
        switch (arg)
        {
            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; }
}

Details of Implementation

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.

Summary

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

Remark

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.

Points of Interest

The reader can find the following links to be interesting:

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

History

  • 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 privileges

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here