elevation demand not working for method in winforms app

2k views Asked by At

I have a winforms app that installs other apps in a loop. This works properly on an administrator account in Windows 7, but I have serious issues in a standard account - the app requires elevation in order to write to "Program Files(x86)" folder.

Therefore I am trying to ask for elevation for a specific method (the one that runs the installers) in a winforms c# app, using this code:

[System.Security.Permissions.PrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Role = @"BUILTIN\Administrators")]

After receiving an error, I learned from the web that before calling the method which carries the above attribute, I need to write this:

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

I did this, and the method still throws the following error:

Request for principal permission failed.

Step by step debugging passes the SetPrincipalPolicy line but, when it reaches the method with the Demand atribute, it just throws the same error, as if the SetPrincipalPolicy never existed.

Am I doing something wrong in setting the Demand attribute properly?

Thank you in advance.

LATER EDIT: as requested here is the code that is supposed to trigger the elevation request when installing the app silently (but does not work):

 WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool hasAdministrativeRight = principal.IsInRole(WindowsBuiltInRole.Administrator);
        if (!hasAdministrativeRight)
        {
            ProcessStartInfo psi = new ProcessStartInfo(file);
            psi.WindowStyle = ProcessWindowStyle.Hidden;
            psi.UseShellExecute = true;
            psi.Verb = "runas";

            //psi.CreateNoWindow = true;
            psi.Arguments = modifiers;
            try
            {
                using (Process process = Process.Start(psi))
                {
                    process.WaitForExit();
                    if (process.HasExited)
                        return process.ExitCode;
                }
            }
            catch (Win32Exception wex)
            {

            }
        }

What I need, is for that process to pop a dialog asking for username and password for admin, if the app was ran under a Windows Standard User. Only the process started programmatically above should run as admin, the main app itself can remain as a standard user.

2

There are 2 answers

9
Oskar Kjellin On BEST ANSWER

You can either force your app to always run as an admin. This is how you do that. It is not recommended however for your app to need admin privileges to run.

If you start a Process to run the installer, you can check here how to run the process as an admin.

A third option which Visual Studio uses is that when you do something where you need admin privileges you are prompted to restart the app and it then restarts the app as an admin and you can perform the tasks. Just use the code from the second way to start your app.

The method you've posted to run as admin will check if the user is admin and then start the process as an admin. If the user doesn't have admin rights the app won't even start. A better solution is to always try to run the process as an admin. Then the user will get an UAC prompt with password and username, which an admin can fill in.

public static int RunAsAdmin(string fileName)
{

        ProcessStartInfo psi = new ProcessStartInfo(fileName);
        psi.WindowStyle = ProcessWindowStyle.Hidden;
        psi.UseShellExecute = true;
        psi.Verb = "runas";
        psi.Arguments = modifiers;

        try
        {
            using (Process process = Process.Start(psi))
            {
                process.WaitForExit();
                if (process.HasExited)
                    return process.ExitCode;
            }
        }
        catch (Win32Exception wex)
        {

        }

    return 0;
}
2
Hans Passant On

This is just not the way UAC works. It is process based, the user only ever gets the "please let me mess with your machine" prompt when you start a new process. With the proper incantation of "I need the user's consent to mess with the machine, please say Yes" signal embedded in the program. Which you do by this answer.

Death to the idea of making it method based. Unreasonable to a programmer, makes sense to a user. User wins.