N
neal.shawn
Below is a class that I use to run code under different Windows
credentials. It does in fact work, but I wonder if I'm exposing myself
to a possible race condition between the GC and my Finalizer? FxCop
flags this class and advises that I should use GC.KeepAlive(). Do I
need to use GC.KeepAlive, and if so where - in the Dispose method?
To use this class from a client program:
RunAs run = new RunAs("otheruser", "domain", "password");
run.LogOn();
// do operation as 'otheruser' here ...
run.LogOff();
public class RunAs : IDisposable
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string principal,
string authority,
string password,
LogonSessionType logonType,
LogonProvider logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
// Win32 mirrored enum
private enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
// Win32 mirrored enum
private enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
private string _userName;
private string _domainName;
private string _password;
private IntPtr _token;
private WindowsImpersonationContext _impersonatedUser;
public RunAs(string userName, string domainName, string password)
{
_userName = userName;
_domainName = domainName;
_password = password;
}
public RunAs(string ntLoginName, string password)
{
string[] login = ntLoginName.Split('\\');
_userName = login[0];
_domainName = login[1];
_password = password;
}
public virtual bool LogOn()
{
bool result = LogonUser(
_userName,
_domainName,
_password,
LogonSessionType.NewCredentials,
LogonProvider.Default,
out _token);
if (result)
{
// create window identity login
WindowsIdentity id = new WindowsIdentity(_token);
// begin impersonation
_impersonatedUser = id.Impersonate();
}
return result;
}
public void LogOff()
{
Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Clean up managed resources
if (_impersonatedUser != null)
_impersonatedUser.Undo();
}
// Clean up unmanaged resources
if (_token != IntPtr.Zero)
CloseHandle(_token);
}
~RunAs()
{
Dispose(false);
}
}
credentials. It does in fact work, but I wonder if I'm exposing myself
to a possible race condition between the GC and my Finalizer? FxCop
flags this class and advises that I should use GC.KeepAlive(). Do I
need to use GC.KeepAlive, and if so where - in the Dispose method?
To use this class from a client program:
RunAs run = new RunAs("otheruser", "domain", "password");
run.LogOn();
// do operation as 'otheruser' here ...
run.LogOff();
public class RunAs : IDisposable
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string principal,
string authority,
string password,
LogonSessionType logonType,
LogonProvider logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
// Win32 mirrored enum
private enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
// Win32 mirrored enum
private enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
private string _userName;
private string _domainName;
private string _password;
private IntPtr _token;
private WindowsImpersonationContext _impersonatedUser;
public RunAs(string userName, string domainName, string password)
{
_userName = userName;
_domainName = domainName;
_password = password;
}
public RunAs(string ntLoginName, string password)
{
string[] login = ntLoginName.Split('\\');
_userName = login[0];
_domainName = login[1];
_password = password;
}
public virtual bool LogOn()
{
bool result = LogonUser(
_userName,
_domainName,
_password,
LogonSessionType.NewCredentials,
LogonProvider.Default,
out _token);
if (result)
{
// create window identity login
WindowsIdentity id = new WindowsIdentity(_token);
// begin impersonation
_impersonatedUser = id.Impersonate();
}
return result;
}
public void LogOff()
{
Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Clean up managed resources
if (_impersonatedUser != null)
_impersonatedUser.Undo();
}
// Clean up unmanaged resources
if (_token != IntPtr.Zero)
CloseHandle(_token);
}
~RunAs()
{
Dispose(false);
}
}