Run a winforms application with elevated permissions

I have a winforms application (c#). It will be deployed to specific users' desktops. When it is run, I need it to run with elevated permissions. Specifically I want it to run with the permissions of an account I specify without having to enter the username and password. What is the best way to implement this? I'm working with visual studio 2017 in a Windows 8 environment.
dodgerfanAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

This technique is called user impersonation.
Here is a code sample

// The following example demonstrates the use of the WindowsIdentity class to impersonate a user.   
// IMPORTANT NOTE:   
// This sample asks the user to enter a password on the console screen.   
// The password will be visible on the screen, because the console window   
// does not support masked input natively.  

using System;  
using System.Runtime.InteropServices;  
using System.Security;  
using System.Security.Principal;  
using Microsoft.Win32.SafeHandles;  

public class ImpersonationDemo  
{  
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]  
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,  
        int dwLogonType, int dwLogonProvider, out SafeAccessTokenHandle phToken);  

    public static void Main()  
    {  
        // Get the user token for the specified user, domain, and password using the   
        // unmanaged LogonUser method.   
        // The local machine name can be used for the domain name to impersonate a user on this machine.  
        Console.Write("Enter the name of the domain on which to log on: ");  
        string domainName = Console.ReadLine();  

        Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);  
        string userName = Console.ReadLine();  

        Console.Write("Enter the password for {0}: ", userName);  

        const int LOGON32_PROVIDER_DEFAULT = 0;  
        //This parameter causes LogonUser to create a primary token.   
        const int LOGON32_LOGON_INTERACTIVE = 2;  

        // Call LogonUser to obtain a handle to an access token.   
        SafeAccessTokenHandle safeAccessTokenHandle;  
        bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),  
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,  
            out safeAccessTokenHandle);  

        if (false == returnValue)  
        {  
            int ret = Marshal.GetLastWin32Error();  
            Console.WriteLine("LogonUser failed with error code : {0}", ret);  
            throw new System.ComponentModel.Win32Exception(ret);  
        }  

        Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));  
        // Check the identity.  
        Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);  

        // Note: if you want to run as unimpersonated, pass  
        //       'SafeAccessTokenHandle.InvalidHandle' instead of variable 'safeAccessTokenHandle'  
        WindowsIdentity.RunImpersonated(  
            safeAccessTokenHandle,  
            // User action  
            () =>  
            {  
                // Check the identity.  
                Console.WriteLine("During impersonation: " + WindowsIdentity.GetCurrent().Name);  
            }  
            );  

        // Check the identity again.  
        Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);  
    }  
}

Open in new window


Please refer to the documentation for more details:
https://docs.microsoft.com/en-us/dotnet/api/system.security.principal.windowsidentity.runimpersonated?view=netframework-4.7.2

Regards,
Chinmay.
0
Scott McDaniel (Microsoft Access MVP - EE MVE )Infotrakker SoftwareCommented:
Specifically I want it to run with the permissions of an account I specify without having to enter the username and password.
You'd have to enter the credentials at some point, otherwise you'd not be able to log in as that account. Do you mean that you're going to embed the credentials into your code, as Chinmay has suggested above?
0
Chinmay PatelChief Technical NinjaCommented:
I think he meant to say manual entry of the credentials.

@dodgerfan,
Please modify the sample above per your requirements. If I were to do it I'd store credentials in a config file and encrypt it using DPAPI.
0
PMI ACP® Project Management

Prepare for the PMI Agile Certified Practitioner (PMI-ACP)® exam, which formally recognizes your knowledge of agile principles and your skill with agile techniques.

dodgerfanAuthor Commented:
Yes, I want to avoid having the user manually enter a username and password. I've using this example:
https://www.daoudisamir.com/impersonate-users-in-c/
which I think comes from the one you put up here. I'm using it, and I've put in the click event of a button. The button is returns a list of files from a selected directory. I'm getting an error message that says: Could not find a part of the path. I'm usually selecting folders from mapped drives. Would that cause this issue? If it does, is there a fix?
0
Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

That method is seriously dated ( I used it extensively in 2003 , If today I have to do impersonation, I would use the latest recommendations by Microsoft. The latest method used for impersonation only uses one Pinvoke call, rest of the stuff is managed.

Now coming to the question, yes I think it is due to mapped drives. I think for the folders which are giving you an error - you can do a retry(time consuming and can be a performance bottleneck) OR highlight it to the end user that the following paths are not accessible - so they can take corrective measures.

Regards,
Chinmay.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
dodgerfanAuthor Commented:
Chinmay, I switched my code to use what you referenced first. I have it working now. But I got an error at first. "The user has not been granted the requested logon type at this computer". After some searching, I changed
const int LOGON32_LOGON_INTERACTIVE = 2; 

Open in new window

to
const int LOGON32_LOGON_INTERACTIVE = 8; 

Open in new window

I'm not sure I understand why that worked. I have not resolved my mapped drive issue yet, but after looking at it it feels like a sparate question. Thank you for your input. If I cannot get it resolved I open a  new question. In the meantime I'm going to close this one.
0
Chinmay PatelChief Technical NinjaCommented:
Whenever in doubt w.r.t. PInvoke, refer to: Pinvoke.net http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html

You are to supply plain-text credentials for your scenario to work. It is strange, I wonder what kind of account you are using?
Please use the proper constants and their values from the Pinvoke.net

nst int LOGON32_LOGON_INTERACTIVE       = 2;
const int LOGON32_LOGON_NETWORK       = 3;
const int LOGON32_LOGON_BATCH         = 4;
const int LOGON32_LOGON_SERVICE       = 5;
const int LOGON32_LOGON_UNLOCK        = 7;
const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
const int LOGON32_LOGON_NEW_CREDENTIALS   = 9;

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.