Avatar of dodgerfan
dodgerfan
Flag for United States of America asked on

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.
.NET ProgrammingC#

Avatar of undefined
Last Comment
Chinmay Patel

8/22/2022 - Mon
Chinmay Patel

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 )

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 Patel

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.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
dodgerfan

ASKER
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?
ASKER CERTIFIED SOLUTION
Chinmay Patel

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
dodgerfan

ASKER
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 Patel

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

Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.