Impersonate user in Windows Service

Ich versuche, einen Domänenbenutzer in einem Windows-Dienst mit dem als lokales Systemkonto angemeldeten Dienst zu übernehmen.

Bisher kann ich dies nur erreichen, indem ich den Dienst protokolliere und den Prozess mit den Benutzeranmeldeinformationen wie den folgenden einstelle.

        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.FileName = CommandDetails.Command;
        startInfo.WorkingDirectory = Settings.RoboCopyWorkingDirectory;
        startInfo.Arguments = commandLine;

        startInfo.UseShellExecute = false;
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardError = true;
        startInfo.RedirectStandardOutput = true;

        // Credentials
        startInfo.Domain = ImperDomain;
        startInfo.UserName = ImperUsername;
        startInfo.Password = ImperPasswordSecure;

        process = Process.Start(startInfo);

Mein Ziel ist es, das Dienstprotokoll nicht in einem Domänenbenutzer, sondern als lokales System zu haben, da die Kennwörter der Domänenkonten zurückgesetzt werden.

Wenn ich das lokale System verwende, erhalte ichAccess wird verweigert

Irgendwelche Ideen, wie das zu erreichen ist?

StackTace

Access is denied

   at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start()
   at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
   at Ace.WindowsService.ProcessCmd.ProcessCommand.StartProcess(ProcessStartInfo startInfo) in 

Ich habe versucht, den Code in den unten aufgelisteten Identitätswechsel-Code einzufügen.

Impersonate Code

public class Impersonation2 : IDisposable
{
    private WindowsImpersonationContext _impersonatedUserContext;

    // Declare signatures for Win32 LogonUser and CloseHandle APIs
    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LogonUser(
      string principal,
      string authority,
      string password,
      LogonSessionType logonType,
      LogonProvider logonProvider,
      out IntPtr token);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr handle);

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

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

    // ReSharper disable UnusedMember.Local
    enum LogonSessionType : uint
    {
        Interactive = 2,
        Network,
        Batch,
        Service,
        NetworkCleartext = 8,
        NewCredentials
    }
    // ReSharper disable InconsistentNaming
    enum LogonProvider : uint
    {
        Default = 0, // default for platform (use this!)
        WinNT35,     // sends smoke signals to authority
        WinNT40,     // uses NTLM
        WinNT50      // negotiates Kerb or NTLM
    }
    // ReSharper restore InconsistentNaming
    // ReSharper restore UnusedMember.Local

    /// <summary>
    /// Class to allow running a segment of code under a given user login context
    /// </summary>
    /// <param name="user">domain\user</param>
    /// <param name="password">user's domain password</param>
    public Impersonation2(string domain, string username, string password)
    {
        var token = ValidateParametersAndGetFirstLoginToken(username, domain, password);

        var duplicateToken = IntPtr.Zero;
        try
        {
            if (DuplicateToken(token, 2, ref duplicateToken) == 0)
            {
                throw new Exception("DuplicateToken call to reset permissions for this token failed");
            }

            var identityForLoggedOnUser = new WindowsIdentity(duplicateToken);
            _impersonatedUserContext = identityForLoggedOnUser.Impersonate();
            if (_impersonatedUserContext == null)
            {
                throw new Exception("WindowsIdentity.Impersonate() failed");
            }
        }
        finally
        {
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (duplicateToken != IntPtr.Zero)
                CloseHandle(duplicateToken);
        }
    }

    private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password)
    {


        if (!RevertToSelf())
        {
            throw new Exception("RevertToSelf call to remove any prior impersonations failed");
            ErrorLogger.LogEvent("RevertToSelf call to remove any prior impersonations failed", System.Diagnostics.EventLogEntryType.Error, "");

        }

        IntPtr token;

        var result = LogonUser(domain, username,
                               password,
                               LogonSessionType.Interactive,
                               LogonProvider.Default,
                               out token);
        if (!result)
        {
            var errorCode = Marshal.GetLastWin32Error();
            ErrorLogger.LogEvent(string.Format("Could not impersonate the elevated user.  LogonUser: {2}\\{1} returned error code: {0}.", errorCode, username, domain), System.Diagnostics.EventLogEntryType.Error, "");
            throw new Exception("Logon for user " + username + " failed.");
        }
        return token;
    }

    public void Dispose()
    {
        // Stop impersonation and revert to the process identity
        if (_impersonatedUserContext != null)
        {
            _impersonatedUserContext.Undo();
            _impersonatedUserContext = null;
        }
    }

Aktualisiere

Dies funktioniert gut, wenn ich gerade laufe, wenn ich es gerade ausführe. Aber wenn es als Dienst ausgeführt wird, funktioniert es nicht

Update 2

Ich erhalte keinen verweigerten Zugriff vom Process.Start, wenn ich die imitierende Anmeldung in LogonSessionType.NewCredentials ändere und die Anmeldeinformationen aus dem Prozess entferne. Jetzt wird jedoch ein Fehler beim Ausführen des Befehls robocopy angezeigt. Wenn ich die Anmeldeinformationen für den Prozess habe, wird vom Robocopy-Befehl @ keine Protokolldatei erstell

Erro

2016/07/16 09:19:12 ERROR 5 (0x00000005) 
Accessing Source Directory \\[server]\[path]\
Access is denied.

Veränderun

var result = LogonUser(domain, username,
   password,
   LogonSessionType.NewCredentials,
   LogonProvider.Default,
   out token);

Update 3

Die Funktionen zum Kopieren und Verschieben funktionieren. Das Erstellen von Unterprozessen ist dies jedoch nicht. Ich habe mit CreateProcessAsUser gespielt, wie Hary Johnston vorgeschlagen hat.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage