Enabling UAC Elevation in .Net applications

Remember, when we run any application in any platform with normal user privileges, the user will not be able to perform any admin operations that’s required as part of application. For example the application needs a new database to be created to maintain the data being used or another example could be writing an application event log. In these kinds of scenarios the application needs admin/power user privileges to perform these operations. Another way of doing it is running the application itself as an administrator. But this prevents the normal user from using the application. Hence the normal user can be enabled with the option of using the application and even perform privileged user operations if he is provided necessary rights, with the help of UAC elevations.

The application will normally throw insufficient rights exception when tried either one of the scenarios given above, without necessary privileges. We can perform these privileged operations by elevating the user to provide the credentials. This gives the user freedom of accessing the basic features.

.Net framework doesn’t provide any library to support elevated admin operation and this need to be done manually with some programming overheads. For which the programming logic that performs admin operation like Database creation, event log creation needs to placed in a separate executable and the executable has to be called from the main program using System.Diagonastics classes to elevate and complete the required operation.

Making an Elevation Call

public static int RunElevated(string exeName, string parameters)

{

int status = 0;

System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();

      startInfo.UseShellExecute = true;

      startInfo.WorkingDirectory = Environment.CurrentDirectory;

startInfo.FileName = exeName;

startInfo.Verb = "runas";

startInfo.Arguments = parameters;

startInfo.ErrorDialog = true;

try

{

System.Diagnostics.Process process = System.Diagnostics.Process.Start(startInfo);

process.WaitForExit();

status = process.ExitCode;

}

catch

{

// Elevated privileges were not set

MessageBox.Show("Failed to gain administator privileges");

status = -1;

}

return status;

}

Checking User previliges

At the same time of making elevation call, we need to make sure we have an option of performing the same admin operation in the host application itself. If the user is a previleged user there is no need for elevation and unnecessary prompting for user credentials.

PerformElevationCheck();

if (ElevationRequired)

{

int status = 1;

if (!string.IsNullOrEmpty(createDbPath) && !string.IsNullOrEmpty(parameters))

status = RunElevated(createDbPath, parameters);

switch (status)

{

case (2):

MessageBox.Show("Login Failed", "Connect to Server", MessageBoxButtons.OK, MessageBoxIcon.Error);

break;

case (0):

creationStatus = bsDbUtilities.SetUpDataBase(selectedServer, databaseName, timeOut, integratedAuthentication, userName, password);

break;

}

}

else

{

creationStatus = bsDbUtilities.CreateDataBaseWithoutElevation(selectedServer, databaseName, timeOut, integratedAuthentication, userName, password);

}

Displaying Elevation icon

Hence before making an elevation call the user credtials needs to be checked and the user can be intimated with an elevation icon if a particualr operation involves user elevation.

private void PerformElevationCheck()

{

AppDomain ad = Thread.GetDomain();

ad.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

WindowsPrincipal user = (WindowsPrincipal)Thread.CurrentPrincipal;

// Decorate Next button with the BCM_SETSHIELD method if the user is an non admin

ElevationRequired = false;

if (!user.IsInRole(WindowsBuiltInRole.Administrator))

{

ElevationRequired = true;

ElevateIcon_BCM_SETSHIELD(btnNext, true);

}

else

ElevateIcon_BCM_SETSHIELD(btnNext, false);

}

        ///////////////////////////////////////////////////////////////////////

/// <summary>

///     P/Invoke setup for user32.dll!SendMessage

/// </summary>

/// <param name="hWnd">

///     Handle to the window whose window procedure will receive the

///     message.

/// </param>

/// <param name="Msg">

///     Specifies the message to be sent.

/// </param>

/// <param name="wParam">

///     Specifies additional message-specific information.

/// </param>

/// <param name="lParam">

///     Specifies additional message-specific information.

/// </param>

/// <returns>

///     Message processing result as a LRESULT.

/// </returns>

        ///////////////////////////////////////////////////////////////////////

[DllImport("user32.dll")]

private static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

///////////////////////////////////////////////////////////////////////

/// <summary>

///     Enables the elevated shield icon on the given button control

/// </summary>

/// <param name="ThisButton">

///     Button control to enable the elevated shield icon on.

/// </param>

        ///////////////////////////////////////////////////////////////////////

private void ElevateIcon_BCM_SETSHIELD(Button ThisButton, bool Enable)

{

// Input validation, validate that ThisControl is not null

if (ThisButton == null)

{

return;

}

// Define BCM_SETSHIELD locally, declared originally in Commctrl.h

uint BCM_SETSHIELD = 0x0000160C;

// Set button style to the system style

ThisButton.FlatStyle = FlatStyle.System;

// Send the BCM_SETSHIELD message to the button control

if (Enable)

SendMessage(new HandleRef(ThisButton, ThisButton.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(1));

else

SendMessage(new HandleRef(ThisButton, ThisButton.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(0));

}

Sample:

 

In this example of database creation clicking on next button would prompt the user to provide/confirm the credentials to continue further.

Thus UAC elevations can be enabled in .net applications to perform admin operations.

Comments

  • Anonymous
    September 15, 2008
    Local Mode Reporting in Desktop Applications Enabling UAC Elevation in .Net Applications