Programming Elevated Privilege/UAC
Running applications with more privileges than required is against the
principle of least privilege, and may have potential security
vulnerability. To defend this, Windows Vista introduces User Account
Control (UAC), to protect operating system by running applications
with reduced privileges (as a normal user), even the current user is
signed in as an administrator. More and more XP/2K users are also use
normal user account for daily use. Read UAC Demystified first to fully
understand UAC.
There are two common mistakes that developers tend to make:
- Request the end-user to run an application with administrator privilege even
though this is not necessary, most of the time because of bad design
practices. These applications either scare away end-users, or
potentially have security vulnerability.
- Do not request the end-user
to run the application elevated but try to perform operations that
require administrator privilege. These applications simply break under
Windows Vista or Windows XP/2K normal user account.
The downloadable sample code demonstrates how to programming elevated
privilege/UAC. Both WPF and Windows Forms sample applications are
provided. Run the application for the following scenarios to see the
difference:
- Normal user, Windows XP/Windows Vista: the UAC shield icon
is displayed. Clicking “Save to C:\” displays “Run As” dialog, asking
user to enter administrator password to continue;
- Administrator, Windows XP/Windows Vista with UAC disabled: the UAC shield icon is
hidden. Clicking “Save to C:\” completed without any dialog;
- Administrator, Windows Vista with UAC enabled: the UAC shield icon is
displayed. Clicking “Save to C:\” displays dialog asking user’s
permission to continue.
Link to Download
Calling the elevated execute (testing for admin first):
private void SaveToRootFolder_Click(object sender, EventArgs e)
{
string fileName = @"C:\Test.txt";
if (App.IsAdmin)
DoSaveFile(textBox1.Text, textBox2.Text, fileName);
else
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Text1", textBox1.Text);
parameters.Add("Text2", textBox2.Text);
parameters.Add("FileName", fileName);
string result = Program.ElevatedExecute(parameters);
if (!string.IsNullOrEmpty(result))
MessageBox.Show(result);
}
}
Elevated Executes:
internal static string ElevatedExecute(NameValueCollection parameters)
{
string tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, ConstructQueryString(parameters));
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
startInfo.FileName = uri.LocalPath;
startInfo.Arguments = "\"" + tempFile + "\"";
startInfo.Verb = "runas";
Process p = Process.Start(startInfo);
p.WaitForExit();
return File.ReadAllText(tempFile);
}
catch (Win32Exception exception)
{
return exception.Message;
}
finally
{
File.Delete(tempFile);
}
}