You can use it over and over again. You have a program that under a
running user other than the logged-on.
This I found a link in MS which shows how to do it, however,
in a console application.
In principle this works too. I have now made me a class, the
me it slightly easier provides.
It has two public static methods. A to the change of identity, the
others return to the old.
Here the code.
/*
Original habe ich bei MS gefunden.
http://msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/cpref/html/frlrfSystemSecurityPrincipalWindowsIdentityClassImpersonateTopic.asp
*/
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Test
{
/// <summary>
/// Zusammenfassung für ChangeIdentity.
/// </summary>
publicclass ChangeIdentity
{
#region Variabeln
/****************************************************************************/
/***** Variablen *****/
/****************************************************************************/
privatestatic IntPtr tokenHandle =new IntPtr(0);
privatestatic IntPtr dupeTokenHandle =new IntPtr(0);
//Deklaration benötigter API-Funktionen und Konstanten
privateconstint LOGON32_PROVIDER_DEFAULT = 0;
privateconstint LOGON32_LOGON_INTERACTIVE = 2;
privateconstint SecurityImpersonation = 2;
[DllImport("advapi32.dll", SetLastError=true)]
privatestaticexternbool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
privatestaticexternunsafeint FormatMessage(int dwFlags, ref IntPtr lpSource, int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
privatestaticexternbool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
privatestaticexternbool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
//Das wird benötigt um die Personifizierung wieder rückgängig zu machen.
privatestatic WindowsImpersonationContext impersonatedUser =null;
/****************************************************************************/
/***** Ende Variablen *****/
/****************************************************************************/
#endregion
#region Methoden
/****************************************************************************/
/***** Methoden *****/
/****************************************************************************/
/// <summary>
/// Wechselt den Benutzer, unter dem das Programm ausgeführt werden soll.
/// </summary>
/// <param name="Domain">Name der Domäne</param>
/// <param name="UserName">User Name, unter dem das Programm laufen soll</param>
/// <param name="Passwort">Das passende Passwort</param>
publicstaticvoid ImpersonateUser(string Domain, string UserName, string Passwort)
{
tokenHandle = IntPtr.Zero;
dupeTokenHandle = IntPtr.Zero;
//Mit dem gewünschten User anmelden.
bool returnValue = LogonUser(UserName, Domain, Passwort, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);
//Bei einem Fehler, z.b. falschen Namen, falsches Passwort, soll eine Exception geworfen werden.
if(false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
string fehler = GetErrorMessage(ret);
string f ="Errorcode: "+ ret.ToString() + Environment.NewLine;
f += fehler;
thrownew Exception(f);
}
//Für was??? Weiss ich nicht so genau. :-)s
bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
if(false == retVal)
{
CloseHandle(tokenHandle);
thrownew Exception("Fehler beim Dublizieren des Token.");
}
//Die Intentität wechseln.
WindowsIdentity newId =new WindowsIdentity(dupeTokenHandle);
impersonatedUser = newId.Impersonate();
//Die Token wieder freigeben.
if(tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
if(dupeTokenHandle != IntPtr.Zero)
CloseHandle(dupeTokenHandle);
}
/*----------------------------------------------------------------------------------------------*/
/// <summary>
/// Die Identität wieder zurücksetzen.
/// </summary>
publicstaticvoid UndoImpersonateUser()
{
if(impersonatedUser !=null)
{
impersonatedUser.Undo();
}
}
/*----------------------------------------------------------------------------------------------*/
/// <summary>
/// Gibt den letzten Win32Error zurück.
/// Habe ich 1:1 aus dem Beispiel übernommen.
/// </summary>
privatestaticunsafestring GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
//int errorCode = 0x5; //ERROR_ACCESS_DENIED
//throw new System.ComponentModel.Win32Exception(errorCode);
int messageSize = 255;
String lpMsgBuf ="";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, &prtArguments);
if(0 == retVal)
{
thrownew Exception("Failed to format message for error code "+ errorCode +". ");
}
return lpMsgBuf;
}
/****************************************************************************/
/***** Ende Methoden *****/
/****************************************************************************/
#endregion
}
}
You can apply them as follows. Made I have it in a WinForm application.
/ / / < summary >
/ / / The main entry point for the application.
/ / / < / summary >
[STAThread]
staticvoid Main()
{
'S application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
try
{
ChangeIdentity.ImpersonateUser ("DOMAIN", "username", "Password");
}
catch(Exception ex)
{
MessageBox.Show (ex.message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.run (new FrmMain());)
ChangeIdentity.UndoImpersonateUser();
}
Keep in mind is that it so much I was sleeping, so simply works only with Windows XP and Windows Server 2003.
On Windows 2000 and NT4, the user running the program must have the privilege SE_TCP_NAME.