Win32 LogonUser & Dispose

  • Thread starter Thread starter neal.shawn
  • Start date Start date
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);
}
}
 
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;
}

I believe the WindowsIdentity constructor duplicates the token. So you
should be able to close your _token right after constructing the
WindowsIdentity instead of in the Dispose method. That should get rid
of the FxCop warning as well.


Mattias
 
Back
Top