Make Your Programs Impersonate
Sometimes it is useful for your Programs to impersonate under a different user's context. The .NET Framework provides a little help for that, but it still requires a litle help from Platform Invoke.
We can impersonate by using the WindowsIdentity class and calling the Impersonate method on it. The only trick is actually getting a WindowsIdentity for another user. It's easy to get get one for the current user, but requires some work.
Let's say I have a Windows Account named "test" with a password of "TeSt111@", but my current Windows Account is "Kevin Jones" with a password of "notreal". However I programically want to run my program as "test".
By using the WindowsIdentity.Impersonate() method, we can impersonate. However this method expects a Windows Token, and getting a hold of one of those requires some unmanaged code. The unmanaged library we will need is advapi32.dll, which contains an entry point called "LogonUser". This is what we will use to get an impersonation token. This entry point needs a few things. It needs a Username, a domain, a password, the login type, and the login provider. It hands back the token as a reference parameter, and returns true or false as to if the logon was successful. The managed P/Invoke wrapper would look something like this:
[DllImport("advapi32.dll", EntryPoint
=
"LogonUser", SetLastError
=
true
)]
public
static
extern
bool
LogonUser(
string
lpszUsername,
string
lpszDomain,
string
lpszPassword,
int
dwLogonType,
int
dwLogonProvider,
ref
IntPtr phToken);
This is a start. Now to get the token for the test account it would require calling this with the correct things, which might look something like this:
IntPtr token
=
IntPtr
.
Zero;
bool
success
=
LogonUser("test",
null
, "TeSt111@",
2
,
0
,
ref
token);
if
(
!
success)
{
throw
new
Exception("An error occured logging in.");
}
WindowsImpersonationContext context
=
WindowsIdentity
.
Impersonate(token);
//At this point in time, the application is now running as a different context
context
.
Undo();
//After undo, it goes back to normal.
CloseHandle(token);
//Release the handle to the token.
You see this other method called "CloseHandle" which is another unmanaged call to the kernel, to release the handle to the token. This method as managed code looks like this:
[DllImport("kernel32.dll", EntryPoint
=
"CloseHandle", SetLastError
=
true
)]
public
static
extern
bool
CloseHandle(IntPtr handle);
Limitations
The only limitation to it is this code assumes you are using a local account, and not Active Directory or that you are on a domain (hence passing null as the domain). In order to do it with a network account, you would need to Duplicate the token, which I will save for another time.