Okt 062005
 

Das kann man immer wieder gebrauchen. Man hat ein Programm, dass unter einem
anderen Benutzer als dem angemeldeten, ausgeführt werden soll.
Dazu habe ich bei MS einen Link gefunden der zeigt, wie man es macht, allerdings
in einer Konsolenanwendung.

 
Im Prinzip funktioniert das auch. Ich habe mir jetzt eine Klasse gemacht, die
mir das ganze einwenig einfacher zur Verfügung stellt.
Sie hat zwei öffentliche statische Methoden. Eine zum ändern der Identität, die
andere um zur alten zurück zu kehren.
Hier der 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
    }
}

Anwenden kann man sie wie folgt. Gemacht habe ich es bei einer WinForm Anwendung.



/// <summary>


/// Der Haupteinstiegspunkt für die Anwendung.

/// </summary>

[STAThread]
staticvoid Main()
{
    Application.ThreadException+=new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

    try
    {
        ChangeIdentity.ImpersonateUser(„DOMAIN“, „USERNAME“, „PASSWORT“);
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message, „Fehler“, MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    Application.Run(new FrmMain());

    ChangeIdentity.UndoImpersonateUser();
}

 
Zu beachten ist, dass es, so viel ich mitbekommen habe, nur mit Windows XP und Windows Server 2003 so einfach funktioniert.
Unter Windows 2000 und NT4 muss der Benutzer, der das Programm ausführt, das Privileg SE_TCP_NAME besitzen.

Sorry, the comment form is closed at this time.