namespace Tools { #region Using directives. // ---------------------------------------------------------------------- using System; using System.Security.Principal; using System.Runtime.InteropServices; using System.ComponentModel; // ---------------------------------------------------------------------- #endregion ///////////////////////////////////////////////////////////////////////// /// /// 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. /// /// /// 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. /// public class Impersonator : IDisposable { // ------------------------------------------------------------------ /// /// 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. /// /// The name of the user to act as. /// The domain name of the user to act as. /// The password of the user to act as. public Impersonator(string userName, string domainName, string password) { ImpersonateValidUser(userName, domainName, password); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { UndoImpersonation(); if (impersonationContext != null) { impersonationContext.Dispose(); } } /// /// Does the actual impersonation. /// /// The name of the user to act as. /// The domain name of the user to act as. /// The password of the user to act as. private void ImpersonateValidUser(string userName, string domainName, string password) { RevertToSelf(); IntPtr token = IntPtr.Zero; try { token = LogOnUser(userName, domainName, password); CreateImpersonationContext(token); } finally { if (token != IntPtr.Zero) { NativeMethods.CloseHandle(token); } } } private static void RevertToSelf() { if (!NativeMethods.RevertToSelf()) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } private static IntPtr LogOnUser(string userName, string domainName, string password) { IntPtr token = IntPtr.Zero; if (NativeMethods.LogonUser(userName, domainName, password, NativeMethods.LOGON32_LOGON_INTERACTIVE, NativeMethods.LOGON32_PROVIDER_DEFAULT, ref token) != 0) { return token; } throw new Win32Exception(Marshal.GetLastWin32Error()); } private void CreateImpersonationContext(IntPtr token) { IntPtr tokenDuplicate = IntPtr.Zero; try { if (NativeMethods.DuplicateToken(token, 2, ref tokenDuplicate) == 0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate)) { impersonationContext = tempWindowsIdentity.Impersonate(); } } finally { if (tokenDuplicate != IntPtr.Zero) { NativeMethods.CloseHandle(tokenDuplicate); } } } /// /// Reverts the impersonation. /// private void UndoImpersonation() { if (impersonationContext != null) { impersonationContext.Undo(); } } private WindowsImpersonationContext impersonationContext = null; private static class NativeMethods { [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal 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)] internal static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); internal const int LOGON32_LOGON_INTERACTIVE = 2; internal const int LOGON32_PROVIDER_DEFAULT = 0; } } }