Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display UAC prompt for file save to restricted location using c#?

When a user saves a file from my application, they currently can't save to restricted locations (like C:). I think this is a good restriction, but I would like to provide a UAC prompt to elevate privileges and allow a user to save in a restricted area.

I've seen lots of answers around this topic that involve spawning a new process with elevated privileges using 'runas'. Also, it seems like this can be done by impersonating another user. From what I understand, both of those methods require a user to provide user credentials.

What I'm wanting to do is basically what Windows itself does. When you try to copy a file to C:\ in Windows 7 (assuming you've got UAC set to its default level), you get the following prompt:

UAC Prompt

Once you click the Continue button with the UAC shield, the file is copied to C:\ with no prompt for credentials (assuming you're logged on with admin privileges).

How can I replicate this behavior in my application for admin users? They shouldn't have to impersonate any other user because they already have admin privileges. Can anyone provide details on what Windows is doing during this process? Are they spawning a new explorer.exe process with elevated privileges?

like image 232
Joseph Tilley Avatar asked May 24 '12 18:05

Joseph Tilley


2 Answers

You need to do what Windows does. And spawn a new process which will run with elevated rights. There are no shortcuts here. The token that is allocated when a process starts is what determines what rights the process has. That token cannot be changed after the process has started. If you need to elevate, you need a new process.

I've seen lots of answers around this topic that involve spawning a new process with elevated privileges using 'runas'. Also, it seems like this can be done by impersonating another user. From what I understand, both of those methods require a user to provide user credentials.

No that's not the case. If the current user is not an admin, then the UAC dialog will prompt for new credentials of a user that does have admin rights. That's the over-the-shoulder UAC dialog. On the other hand, if the current user is an admin then they just get the consent dialog. That's the dialog that's shown on the secure desktop and just asks for you to click Continue.

The one thing that Windows components can do that you cannot is start a process elevated without showing you the consent dialog. That happens on Windows 7 only (not on Vista), and only if you have the UAC setting at the new Default setting that was added in Windows 7. That's how Explorer is able to show the dialog that you included in the question and then start an elevated process to do the copying without showing the consent UAC dialog. Only Windows components are granted that ability.

But the bottom line is that you need to start a new process that runs elevated. Using the runas verb is the canonical way to do it.

like image 171
David Heffernan Avatar answered Oct 13 '22 01:10

David Heffernan


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);
        }
    }
like image 20
Mike McMahon Avatar answered Oct 13 '22 00:10

Mike McMahon