We help IT Professionals succeed at work.

Run a winforms application with elevated permissions

dodgerfan
dodgerfan asked
on
193 Views
Last Modified: 2018-10-10
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.
Comment
Watch Question

Chinmay PatelChief Technology Ninja
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
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.
Scott McDaniel (EE MVE )Infotrakker Software
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2014

Commented:
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?
Chinmay PatelChief Technology Ninja
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
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.

Author

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?
Chief Technology Ninja
CERTIFIED EXPERT
Distinguished Expert 2019
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION

Author

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.
Chinmay PatelChief Technology Ninja
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
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

Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.