1

I try to impersonate a specific part of my c# winforms application as domain admin but getting permission errors.

The executed code is quite simple. If i execute this bit of code as user "max neumann" it will show a popup "DE123450\max-neumann" and after the impersonator "DE12345\Administrator" which is the domain admin (or local admin), so the impersonation works fine.

    MessageBox.Show(WindowsIdentity.GetCurrent().Name);
    new Impersonator("Administrator", "DE123450", "Password");
    MessageBox.Show(WindowsIdentity.GetCurrent().Name);
    if(!Directory.Exists(installationPath))
    {
        Directory.CreateDirectory(installationPath);
    }

On Directory.CreateDirectory I get this error which pointing out, that the actual user has not enough rights to create a directory at this path. I dont understand why thats happening.

System.UnauthorizedAccessException: "Der Zugriff auf den Pfad "C:\Program Files (x86)\TEST" wurde verweigert."

If I run the program as administrator its working as expected. Can someone point me in the right direction?

I used the impersonator class from this website https://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User

Impersonator.cs

namespace AtbasNetClientInstaller.Functions
{
    #region Using directives.
    // ----------------------------------------------------------------------

    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    // ----------------------------------------------------------------------
    #endregion

    /////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>    
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///        ...
    ///        using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///        {
    ///            ...
    ///            [code that executes under the new context]
    ///            ...
    ///        }
    ///        ...
    /// 
    /// Please contact the author Uwe Keim (mailto:uwe.keim@zeta-software.de)
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password )
        {
            ImpersonateValidUser( userName, domainName, password );
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.
        // ------------------------------------------------------------------

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.
        // ------------------------------------------------------------------

        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);
        
        [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
        private static extern  bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName, 
            string domain, 
            string password )
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if ( RevertToSelf() )
                {
                    if ( LogonUser(
                        userName, 
                        domain, 
                        password, 
                        LOGON32_LOGON_INTERACTIVE,
                        LOGON32_PROVIDER_DEFAULT, 
                        ref token ) != 0 )
                    {
                        if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
                        {
                            tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
                            impersonationContext = tempWindowsIdentity.Impersonate();
                        }
                        else
                        {
                            throw new Win32Exception( Marshal.GetLastWin32Error() );
                        }
                    }
                    else
                    {
                        throw new Win32Exception( Marshal.GetLastWin32Error() );
                    }
                }
                else
                {
                    throw new Win32Exception( Marshal.GetLastWin32Error() );
                }
            }
            finally
            {
                if ( token!= IntPtr.Zero )
                {
                    CloseHandle( token );
                }
                if ( tokenDuplicate!=IntPtr.Zero )
                {
                    CloseHandle( tokenDuplicate );
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if ( impersonationContext!=null )
            {
                impersonationContext.Undo();
            }    
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }

    /////////////////////////////////////////////////////////////////////////
}
  • 1
    That code cannot impersonate an administrator account with actual administrative permissions, as that requires elevation. The simplest way to do what you want is to delegate to a separate helper executable that [elevates on startup](https://stackoverflow.com/a/2818776/4137916), which avoids the need for interop and the potential failure modes of impersonation as well (as not every call supports it). – Jeroen Mostert Nov 08 '22 at 15:12
  • 1
    Note that launching an application with elevation requires the user to supply credentials. If this isn't an option (because they're not supposed to know these credentials) the setup above is flawed to begin with, as it's directly embedding the credentials in the application, making them fairly easy to intercept. You're better off using something like Group Policy to launch/schedule your application as a local administrator. Performing operations on a machine as a *domain* administrator is a very dubious practice that opens up serious potential for abuse, and should never be necessary. – Jeroen Mostert Nov 08 '22 at 15:22

0 Answers0