c # - Udgiver en Windows-bruger

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg bruger koden til at efterligne en brugerkonto for at få adgang til en fildeling.


public class Impersonator :
    IDisposable
{
    #region Public methods.
    // ------------------------------------------------------------------

    /// <summary>
    /// Constructor. Starts the impersonation with the given credentials.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <param name="userName">The name of the user to act as.</param>
    /// <param name="domainName">The domain name of the user to act as.</param>
    /// <param name="password">The password of the user to act as.</param>
    public Impersonator(
        string userName,
        string domainName,
        string password )
    {
        ImpersonateValidUser( userName, domainName, password );
    }

    // ------------------------------------------------------------------
    #endregion

    #region IDisposable member.
    // ------------------------------------------------------------------

    public void Dispose()
    {
        UndoImpersonation();
    }

    // ------------------------------------------------------------------
    #endregion

    #region P/Invoke.
    // ------------------------------------------------------------------

    [DllImport("advapi32.dll", SetLastError=true)]
    private static extern int LogonUser(
        string lpszUserName,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern int DuplicateToken(
        IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern bool RevertToSelf();

    [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
    private static extern  bool CloseHandle(
        IntPtr handle);

    private const int LOGON32\_LOGON\_INTERACTIVE = 2;
    private const int LOGON32\_PROVIDER\_DEFAULT = 0;

    // ------------------------------------------------------------------
    #endregion

    #region Private member.
    // ------------------------------------------------------------------

    /// <summary>
    /// Does the actual impersonation.
    /// </summary>
    /// <param name="userName">The name of the user to act as.</param>
    /// <param name="domainName">The domain name of the user to act as.</param>
    /// <param name="password">The password of the user to act as.</param>
    private void ImpersonateValidUser(
        string userName, 
        string domain, 
        string password )
    {
        WindowsIdentity tempWindowsIdentity = null;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        try
        {
            if ( RevertToSelf() )
            {
                if ( LogonUser(
                    userName, 
                    domain, 
                    password, 
                    LOGON32\_LOGON\_INTERACTIVE,
                    LOGON32\_PROVIDER\_DEFAULT, 
                    ref token ) != 0 )
                {
                    if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
                    {
                        tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
                        impersonationContext = tempWindowsIdentity.Impersonate();
                    }
                    else
                    {
                        throw new Win32Exception( Marshal.GetLastWin32Error() );
                    }
                }
                else
                {
                    throw new Win32Exception( Marshal.GetLastWin32Error() );
                }
            }
            else
            {
                throw new Win32Exception( Marshal.GetLastWin32Error() );
            }
        }
        finally
        {
            if ( token!= IntPtr.Zero )
            {
                CloseHandle( token );
            }
            if ( tokenDuplicate!=IntPtr.Zero )
            {
                CloseHandle( tokenDuplicate );
            }
        }
    }

    /// <summary>
    /// Reverts the impersonation.
    /// </summary>
    private void UndoImpersonation()
    {
        if ( impersonationContext!=null )
        {
            impersonationContext.Undo();
        }   
    }

    private WindowsImpersonationContext impersonationContext = null;

    // ------------------------------------------------------------------
    #endregion
}


Brug derefter:


using (new Impersonator("username", "domain", "password"))
        {
            Process.Start("explorer.exe", @"/root,\server01-Prodabc");
        }


Jeg får en 'Access Denied' -fejl.


Denne bruger har supposely adgang til denne andel. Jeg kan kortlægge et drev, brug 'netbrug', men denne kode vil ikke fungere. Nu tænker jeg, det er koden. Ser nogen noget? Er der en bedre måde at gøre dette på?

Bedste reference


Prøv dette :


[DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(
            string lpszUsername,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            out IntPtr phToken);


Anvendelse:


IntPtr userToken = IntPtr.Zero;

bool success = External.LogonUser(
  "john.doe", 
  "domain.com", 
  "MyPassword", 
  (int) AdvApi32Utility.LogonType.LOGON32\_LOGON\_INTERACTIVE, //2
  (int) AdvApi32Utility.LogonProvider.LOGON32\_PROVIDER\_DEFAULT, //0
  out userToken);

if (!success)
{
  throw new SecurityException("Logon user failed");
}

using (WindowsIdentity.Impersonate(userToken))
{
 Process.Start("explorer.exe", @"/root,\server01-Prodabc");
}

Andre referencer 1


Hvis jeg forstår korrekt, har du til hensigt at køre processen i efterligningskonteksten.


Dokumentet fra CreateProcess (som bruges af Process.Start) siger:
Hvis opkaldsprocessen efterligner en anden bruger, bruger den nye proces token til opkaldsprocessen, ikke efterligningstokenet. For at køre den nye proces i sikkerhedskonteksten for den bruger, der repræsenteres af efterligningstokenet, skal du bruge CreateProcessAsUser eller CreateProcessWithLogonW-funktionen.


Så bruger du den forkerte API til at gøre det.

Andre referencer 2


Hvad sker der, når du ringer til Process.Start og i stedet for at bruge din Impersonator klasse til en ProcessStartInfo instans, der indeholder brugernavnet, adgangskoden og domænet, som du vil køre processen som? [11]


Måske, hvis det virker, skal din Impersonator klasse oprette en ProcessStartInfo eksempel og bruge det til at skabe nye processer (indkapsler det inden for selve klassen).


var psi = new ProcessStartInfo("explorer.exe", @"/root,\server01-Prodabc");
psi.Domain = domain;
psi.UserName = username;
psi.Password = password;
psi.WorkingDirectory = workingDir;

Process.Start(psi);


Også, ved MSDN-dokumenterne ... [12]



  Indstilling af domæne, brugernavn og adgangskodeegenskaber i a
  ProcessStartInfo-objekt er den anbefalede praksis for at starte en
  behandle med brugeroplysninger.



Du bør også indstille arbejdsmappen, når du starter en proces med forskellige brugerprofiler.