From bc29337460ead999fad77acbcc2a8ebc639b7076 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 19 Dec 2018 10:14:53 -0800 Subject: [PATCH] Fix 'Debug-Runspace' for Unix platforms and properly enable Windows identity impersonation code (#8451) --- .../engine/Utils.cs | 107 +++++++++++------- .../engine/hostifaces/LocalPipeline.cs | 107 ++++++++++-------- .../engine/remoting/client/remoterunspace.cs | 56 ++++----- .../remoting/fanin/BaseTransportManager.cs | 10 +- .../remoting/fanin/WSManTransportManager.cs | 75 +++++------- .../server/OutOfProcServerMediator.cs | 34 +++--- .../server/ServerRunspacePoolDriver.cs | 69 +++++------ 7 files changed, 229 insertions(+), 229 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 7871be6aae..0b7b68226d 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1,34 +1,36 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Security; -using System.Runtime.InteropServices; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.ComponentModel; using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Management.Automation.Security; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +#if !UNIX +using System.Security.Principal; +#endif +using System.Text; +using System.Threading; using Microsoft.PowerShell.Commands; using Microsoft.Win32; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Collections; -using System.Collections.ObjectModel; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Text; +using Microsoft.Win32.SafeHandles; using TypeTable = System.Management.Automation.Runspaces.TypeTable; -using System.Diagnostics; -using Microsoft.Win32.SafeHandles; - namespace System.Management.Automation { /// @@ -870,6 +872,40 @@ namespace System.Management.Automation return result; } +#if !UNIX + private static bool TryGetWindowsCurrentIdentity(out WindowsIdentity currentIdentity) + { + try + { + currentIdentity = WindowsIdentity.GetCurrent(); + } + catch (SecurityException) + { + currentIdentity = null; + } + + return (currentIdentity != null); + } + + /// + /// Gets the current impersonating Windows identity, if any + /// + /// Current impersonated Windows identity or null + /// True if current identity is impersonated + internal static bool TryGetWindowsImpersonatedIdentity(out WindowsIdentity impersonatedIdentity) + { + WindowsIdentity currentIdentity; + if (TryGetWindowsCurrentIdentity(out currentIdentity) && (currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) + { + impersonatedIdentity = currentIdentity; + return true; + } + + impersonatedIdentity = null; + return false; + } +#endif + internal static bool IsAdministrator() { // Porting note: only Windows supports the SecurityPrincipal API of .NET. Due to @@ -881,10 +917,13 @@ namespace System.Management.Automation #if UNIX return true; #else - System.Security.Principal.WindowsIdentity currentIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); - System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(currentIdentity); - - return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); + WindowsIdentity currentIdentity; + if (TryGetWindowsCurrentIdentity(out currentIdentity)) + { + var principal = new WindowsPrincipal(currentIdentity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + return false; #endif } @@ -1171,7 +1210,7 @@ namespace System.Management.Automation internal static readonly UTF8Encoding utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); -#if !CORECLR // TODO:CORECLR - WindowsIdentity.Impersonate() is not available. Use WindowsIdentity.RunImpersonated to replace it. +#if !UNIX /// /// Queues a CLR worker thread with impersonation of provided Windows identity. /// @@ -1197,28 +1236,14 @@ namespace System.Management.Automation WaitCallback callback = args[1] as WaitCallback; object state = args[2]; - WindowsImpersonationContext impersonationContext = null; - if ((identityToImpersonate != null) && - (identityToImpersonate.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) + if (identityToImpersonate != null) { - impersonationContext = identityToImpersonate.Impersonate(); - } - try - { - callback(state); - } - finally - { - if (impersonationContext != null) - { - try - { - impersonationContext.Undo(); - impersonationContext.Dispose(); - } - catch (System.Security.SecurityException) { } - } + WindowsIdentity.RunImpersonated( + identityToImpersonate.AccessToken, + () => callback(state)); + return; } + callback(state); } #endif diff --git a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs index e3512e379b..45bce3a05b 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs @@ -1,15 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Diagnostics; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; -using System.Threading; -using Microsoft.Win32; using System.Management.Automation.Internal; using System.Management.Automation.Internal.Host; using System.Management.Automation.Tracing; +#if !UNIX +using System.Security.Principal; +#endif +using System.Threading; using Microsoft.PowerShell.Commands; +using Microsoft.Win32; using Dbg = System.Management.Automation.Diagnostics; @@ -152,13 +155,29 @@ namespace System.Management.Automation.Runspaces PSThreadOptions memberOptions = this.IsNested ? PSThreadOptions.UseCurrentThread : this.LocalRunspace.ThreadOptions; +#if !UNIX + // Use thread proc that supports impersonation flow for new thread start. + ThreadStart invokeThreadProcDelegate = InvokeThreadProcImpersonate; + _identityToImpersonate = null; + + // If impersonation identity flow is requested, then get current thread impersonation, if any. + if ((InvocationSettings != null) && InvocationSettings.FlowImpersonationPolicy) + { + Utils.TryGetWindowsImpersonatedIdentity(out _identityToImpersonate); + } +#else + // UNIX does not support thread impersonation flow. + ThreadStart invokeThreadProcDelegate = InvokeThreadProc; +#endif + switch (memberOptions) { case PSThreadOptions.Default: case PSThreadOptions.UseNewThread: { - // Start execution of pipeline in another thread - Thread invokeThread = new Thread(new ThreadStart(this.InvokeThreadProc), DefaultPipelineStackSize); + // Start execution of pipeline in another thread, + // and support impersonation flow as needed (Windows only). + Thread invokeThread = new Thread(new ThreadStart(invokeThreadProcDelegate), DefaultPipelineStackSize); SetupInvokeThread(invokeThread, true); #if !CORECLR // No ApartmentState in CoreCLR @@ -187,16 +206,18 @@ namespace System.Management.Automation.Runspaces { if (this.IsNested) { - // if this a nested pipeline we are already in the appropriate thread so we just execute the pipeline here + // If this a nested pipeline we are already in the appropriate thread so we just execute the pipeline here. + // Impersonation flow (Windows only) is not needed when using existing thread. SetupInvokeThread(Thread.CurrentThread, true); - this.InvokeThreadProc(); + InvokeThreadProc(); } else { - // otherwise we execute the pipeline in the Runspace's thread + // Otherwise we execute the pipeline in the Runspace's thread, + // and support information flow on new thread as needed (Windows only). PipelineThread invokeThread = this.LocalRunspace.GetPipelineThread(); SetupInvokeThread(invokeThread.Worker, true); - invokeThread.Start(this.InvokeThreadProc); + invokeThread.Start(invokeThreadProcDelegate); } break; } @@ -210,9 +231,10 @@ namespace System.Management.Automation.Runspaces try { - // prepare invoke thread + // Prepare invoke thread. + // Impersonation flow (Windows only) is not needed when using existing thread. SetupInvokeThread(Thread.CurrentThread, false); - this.InvokeThreadProc(); + InvokeThreadProc(); } finally { @@ -508,8 +530,26 @@ namespace System.Management.Automation.Runspaces return flowControlException; } - // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 - // Removed HandleUnexpectedExceptions infrastructure +#if !UNIX + /// + /// Invokes the InvokeThreadProc() method on new thread, and flows calling thread + /// impersonation as needed. + /// + private void InvokeThreadProcImpersonate() + { + if (_identityToImpersonate != null) + { + WindowsIdentity.RunImpersonated( + _identityToImpersonate.AccessToken, + () => InvokeThreadProc()); + + return; + } + + InvokeThreadProc(); + } +#endif + /// /// Start thread method for asynchronous pipeline execution. /// @@ -520,19 +560,6 @@ namespace System.Management.Automation.Runspaces try { -#if !CORECLR // Impersonation is not supported in CoreCLR. - // Used to store old impersonation context if we impersonate. - System.Security.Principal.WindowsImpersonationContext oldImpersonationCtxt = null; - try - { - if ((InvocationSettings != null) && (InvocationSettings.FlowImpersonationPolicy)) - { - // we have a valid identity to impersonate. - System.Security.Principal.WindowsIdentity identityToImPersonate = - new System.Security.Principal.WindowsIdentity(InvocationSettings.WindowsIdentityToImpersonate.Token); - oldImpersonationCtxt = identityToImPersonate.Impersonate(); - } -#endif // Set up pipeline internal host if it is available. if (InvocationSettings != null && InvocationSettings.Host != null) { @@ -575,29 +602,6 @@ namespace System.Management.Automation.Runspaces // Invoke finished successfully. Set state to Completed. SetPipelineState(PipelineState.Completed); } -#if !CORECLR - } - finally - { - // Impersonation is not supported in CoreCLR. - // This finally block is needed to handle fxcop CA2124 - // If sensitive operations such as impersonation occur in the try block, and an - // exception is thrown, the filter can execute before the finally block. For the - // impersonation example, this means that the filter would execute as the impersonated user. - if (oldImpersonationCtxt != null) - { - try - { - oldImpersonationCtxt.Undo(); - oldImpersonationCtxt.Dispose(); - oldImpersonationCtxt = null; - } - catch (System.Security.SecurityException) - { - } - } - } -#endif } catch (PipelineStoppedException ex) { @@ -1101,12 +1105,15 @@ namespace System.Management.Automation.Runspaces } } - // NTRAID#Windows Out Of Band Releases-925566-2005/12/09-JonN private bool _useExternalInput; private PipelineWriter _oldExternalErrorOutput; private PipelineWriter _oldExternalSuccessOutput; +#if !UNIX + private WindowsIdentity _identityToImpersonate; +#endif + #endregion private_fields #region invoke_loop_detection diff --git a/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs b/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs index 23a988cba8..cfd4a3cdc1 100644 --- a/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs +++ b/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs @@ -1,21 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Management.Automation.Runspaces; -using System.Management.Automation.Host; -using System.Management.Automation.Internal; -using System.Management.Automation.Tracing; -using Dbg = System.Management.Automation.Diagnostics; -using System.Threading; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Management.Automation.Remoting; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using Microsoft.PowerShell.Commands; -using System.Security.Principal; +using System.Management.Automation.Host; +using System.Management.Automation.Internal; +using System.Management.Automation.Remoting; +using System.Management.Automation.Runspaces; using System.Management.Automation.Runspaces.Internal; +using System.Management.Automation.Tracing; +#if !UNIX +using System.Security.Principal; +#endif +using System.Threading; +using Microsoft.PowerShell.Commands; + +using Dbg = System.Management.Automation.Diagnostics; #pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings @@ -1806,9 +1809,11 @@ namespace System.Management.Automation private UnhandledBreakpointProcessingMode _unhandledBreakpointMode; private bool _detachCommand; - // Impersonation flow +#if !UNIX + // Windows impersonation flow private WindowsIdentity _identityToPersonate; private bool _identityPersonationChecked; +#endif /// /// RemoteDebuggerStopEvent @@ -2197,11 +2202,13 @@ namespace System.Management.Automation _runspace.RemoteDebuggerStop -= HandleForwardedDebuggerStopEvent; _runspace.RemoteDebuggerBreakpointUpdated -= HandleForwardedDebuggerBreakpointUpdatedEvent; +#if !UNIX if (_identityToPersonate != null) { _identityToPersonate.Dispose(); _identityToPersonate = null; } +#endif } #endregion @@ -2378,16 +2385,17 @@ namespace System.Management.Automation if (!invokedOnBlockedThread) { -#if CORECLR - Threading.ThreadPool.QueueUserWorkItem( - ProcessDebuggerStopEventProc, - args); -#else // Otherwise run on worker thread. +#if !UNIX Utils.QueueWorkItemWithImpersonation( _identityToPersonate, ProcessDebuggerStopEventProc, args); +#else + Threading.ThreadPool.QueueUserWorkItem( + ProcessDebuggerStopEventProc, + args); + #endif } } @@ -2503,19 +2511,15 @@ namespace System.Management.Automation throw new InvalidRunspaceStateException(); } +#if !UNIX if (!_identityPersonationChecked) { _identityPersonationChecked = true; // Save identity to impersonate. - WindowsIdentity currentIdentity = null; - try - { - currentIdentity = WindowsIdentity.GetCurrent(); - } - catch (System.Security.SecurityException) { } - _identityToPersonate = ((currentIdentity != null) && (currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) ? currentIdentity : null; + Utils.TryGetWindowsImpersonatedIdentity(out _identityToPersonate); } +#endif } private void SetRemoteDebug(bool remoteDebug, RunspaceAvailability? availability) @@ -2574,12 +2578,12 @@ namespace System.Management.Automation } } - #endregion +#endregion } - #endregion +#endregion - #region RemoteSessionStateProxy +#region RemoteSessionStateProxy internal class RemoteSessionStateProxy : SessionStateProxy { @@ -2981,5 +2985,5 @@ namespace System.Management.Automation } } - #endregion +#endregion } diff --git a/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs index 5651af9298..63d4d71c23 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs @@ -15,7 +15,7 @@ using System.Collections.Generic; using System.Globalization; using System.Threading; using System.Management.Automation.Internal; -#if !CORECLR +#if !UNIX using System.Security.Principal; #endif @@ -735,11 +735,9 @@ namespace System.Management.Automation.Remoting.Client _isServicingCallbacks = true; // Start a thread pool thread to process callbacks. -#if !CORECLR - // Flow thread impersonation as needed. - WindowsIdentity identityToImpersonate = WindowsIdentity.GetCurrent(); - identityToImpersonate = (identityToImpersonate.ImpersonationLevel == TokenImpersonationLevel.Impersonation) ? - identityToImpersonate : null; +#if !UNIX + WindowsIdentity identityToImpersonate; + Utils.TryGetWindowsImpersonatedIdentity(out identityToImpersonate); Utils.QueueWorkItemWithImpersonation( identityToImpersonate, diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs index 1ed9072e90..9d929ba0ae 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs @@ -7,24 +7,20 @@ * */ -using System.Management.Automation.Tracing; -using System.IO; -using System.Xml; using System.Collections.Generic; -using System.Globalization; -using System.Threading; -using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; using System.Management.Automation.Internal; -#if !CORECLR +using System.Management.Automation.Remoting.Server; +using System.Management.Automation.Runspaces.Internal; +using System.Management.Automation.Tracing; +using System.Runtime.InteropServices; +#if !UNIX using System.Security.Principal; #endif - -// Don't expose the System.Management.Automation namespace here. This is transport layer -// and it shouldn't know anything about the engine. -using System.Management.Automation.Remoting.Server; -// TODO: this seems ugly...Remoting datatypes should be in remoting namespace -using System.Management.Automation.Runspaces.Internal; +using System.Xml; +using System.Threading; using PSRemotingCryptoHelper = System.Management.Automation.Internal.PSRemotingCryptoHelper; using WSManConnectionInfo = System.Management.Automation.Runspaces.WSManConnectionInfo; @@ -2591,7 +2587,7 @@ namespace System.Management.Automation.Remoting.Client // Dispose private bool _isDisposed; private object _syncObject = new object(); -#if !CORECLR +#if !UNIX private WindowsIdentity _identityToImpersonate; #endif @@ -2600,11 +2596,9 @@ namespace System.Management.Automation.Remoting.Client /// internal WSManAPIDataCommon() { -#if !CORECLR +#if !UNIX // Check for thread impersonation and save identity for later de-initialization. - _identityToImpersonate = WindowsIdentity.GetCurrent(); - _identityToImpersonate = (_identityToImpersonate.ImpersonationLevel == TokenImpersonationLevel.Impersonation) ? - _identityToImpersonate : null; + Utils.TryGetWindowsImpersonatedIdentity(out _identityToImpersonate); #endif _handle = IntPtr.Zero; @@ -2673,42 +2667,25 @@ namespace System.Management.Automation.Remoting.Client if (IntPtr.Zero != _handle) { -#if !CORECLR - // If we initialized with thread impersonation make sure de-initialize is run with same. - WindowsImpersonationContext impersonationContext = null; + int result = 0; + +#if !UNIX + // If we initialized with thread impersonation, make sure de-initialize is run with the same. if (_identityToImpersonate != null) { - try - { - _identityToImpersonate.Impersonate(); - } - catch (ObjectDisposedException) - { - _handle = IntPtr.Zero; - return; - } + result = WindowsIdentity.RunImpersonated( + _identityToImpersonate.AccessToken, + () => WSManNativeApi.WSManDeinitialize(_handle, 0)); } + else + { +#endif + result = WSManNativeApi.WSManDeinitialize(_handle, 0); +#if !UNIX + } +#endif - try - { -#endif - int result = WSManNativeApi.WSManDeinitialize(_handle, 0); Dbg.Assert(result == 0, "WSManDeinitialize returned non-zero value"); -#if !CORECLR - } - finally - { - if (impersonationContext != null) - { - try - { - impersonationContext.Undo(); - impersonationContext.Dispose(); - } - catch (System.Security.SecurityException) { } - } - } -#endif _handle = IntPtr.Zero; } } diff --git a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs index f80fd8c30f..31ad5fa8bd 100644 --- a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs +++ b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs @@ -1,12 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Management.Automation.Tracing; using System.IO; -using System.Threading; -using System.Security.Principal; using System.Management.Automation.Internal; +using System.Management.Automation.Tracing; +using System.Threading; +#if !UNIX +using System.Security.Principal; +#endif using Microsoft.Win32.SafeHandles; + using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation.Remoting.Server @@ -26,8 +29,10 @@ namespace System.Management.Automation.Remoting.Server protected string _initialCommand; protected ManualResetEvent allcmdsClosedEvent; +#if !UNIX // Thread impersonation. protected WindowsIdentity _windowsIdentityToImpersonate; +#endif /// /// Count of commands in progress @@ -350,13 +355,13 @@ namespace System.Management.Automation.Remoting.Server // process data in a thread pool thread..this way Runspace, Command // data can be processed concurrently. -#if CORECLR - ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessingThreadStart), data); -#else +#if !UNIX Utils.QueueWorkItemWithImpersonation( - _windowsIdentityToImpersonate, - new WaitCallback(ProcessingThreadStart), - data); + _windowsIdentityToImpersonate, + new WaitCallback(ProcessingThreadStart), + data); +#else + ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessingThreadStart), data); #endif } while (true); } @@ -591,15 +596,8 @@ namespace System.Management.Automation.Remoting.Server originalStdErr = new NamedPipeErrorTextWriter(namedPipeServer.TextWriter); #if !UNIX - // Flow impersonation if requested. - WindowsIdentity currentIdentity = null; - try - { - currentIdentity = WindowsIdentity.GetCurrent(); - } - catch (System.Security.SecurityException) { } - _windowsIdentityToImpersonate = ((currentIdentity != null) && (currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) ? - currentIdentity : null; + // Flow impersonation as needed. + Utils.TryGetWindowsImpersonatedIdentity(out _windowsIdentityToImpersonate); #endif } diff --git a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs index 9035e16195..faa6e37551 100644 --- a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs +++ b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs @@ -4,18 +4,21 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Concurrent; +using System.Diagnostics; using System.Globalization; using System.Linq; -using System.Management.Automation.Runspaces; using System.Management.Automation.Host; using System.Management.Automation.Internal; using System.Management.Automation.Remoting; using System.Management.Automation.Remoting.Server; -using Dbg = System.Management.Automation.Diagnostics; -using System.Threading; +using System.Management.Automation.Runspaces; using System.Management.Automation.Security; -using System.Diagnostics; +#if !UNIX using System.Security.Principal; +#endif +using System.Threading; + +using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation { @@ -2037,7 +2040,9 @@ namespace System.Management.Automation private PSDataCollection _output; private DebuggerCommandResults _results; private Exception _exception; +#if !UNIX private WindowsIdentity _identityToImpersonate; +#endif // Constructors private ThreadCommandProcessing() { } @@ -2057,14 +2062,10 @@ namespace System.Management.Automation // Methods public DebuggerCommandResults Invoke(ManualResetEventSlim startInvokeEvent) { +#if !UNIX // Get impersonation information to flow if any. - WindowsIdentity currentIdentity = null; - try - { - currentIdentity = WindowsIdentity.GetCurrent(); - } - catch (System.Security.SecurityException) { } - _identityToImpersonate = ((currentIdentity != null) && (currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) ? currentIdentity : null; + Utils.TryGetWindowsImpersonatedIdentity(out _identityToImpersonate); +#endif // Signal thread to process command. Dbg.Assert(!_commandCompleteEvent.IsSet, "Command complete event shoulds always be non-signaled here."); @@ -2074,8 +2075,13 @@ namespace System.Management.Automation // Wait for completion. _commandCompleteEvent.Wait(); _commandCompleteEvent.Reset(); - - _identityToImpersonate = null; +#if !UNIX + if (_identityToImpersonate != null) + { + _identityToImpersonate.Dispose(); + _identityToImpersonate = null; + } +#endif // Propagate exception. if (_exception != null) @@ -2098,18 +2104,17 @@ namespace System.Management.Automation internal void DoInvoke() { -#if !CORECLR // TODO:CORECLR - WindowsIdentity.Impersonate() is not available. Use WindowsIdentity.RunImplemented to replace it. - // Flow impersonation onto thread if needed. - WindowsImpersonationContext impersonationContext = null; - if ((_identityToImpersonate != null) && - (_identityToImpersonate.ImpersonationLevel == TokenImpersonationLevel.Impersonation)) - { - impersonationContext = _identityToImpersonate.Impersonate(); - } -#endif - try { +#if !UNIX + if (_identityToImpersonate != null) + { + _results = WindowsIdentity.RunImpersonated( + _identityToImpersonate.AccessToken, + () =>_wrappedDebugger.ProcessCommand(_command, _output)); + return; + } +#endif _results = _wrappedDebugger.ProcessCommand(_command, _output); } catch (Exception e) @@ -2119,19 +2124,6 @@ namespace System.Management.Automation finally { _commandCompleteEvent.Set(); - -#if !CORECLR // TODO:CORECLR - WindowsIdentity.Impersonate() is not available. Use WindowsIdentity.RunImplemented to replace it. - // Restore previous context to thread. - if (impersonationContext != null) - { - try - { - impersonationContext.Undo(); - impersonationContext.Dispose(); - } - catch (System.Security.SecurityException) { } - } -#endif } } } @@ -2317,7 +2309,7 @@ namespace System.Management.Automation if (isNestedStop) { - // Blocking call for nested debugger execution (Workflow) stop events. + // Blocking call for nested debugger execution (Debug-Runspace) stop events. // The root debugger never makes two EnterDebugMode calls without an ExitDebugMode. if (_nestedDebugStopCompleteEvent == null) { @@ -2494,8 +2486,7 @@ namespace System.Management.Automation bool addToHistory) { // For nested debugger command processing, invoke command on new local runspace since - // the root script debugger runspace is unavailable (it is running a PS script or a - // workflow function script). + // the root script debugger runspace is unavailable (it is running a PS script). Runspace runspace = (remoteHost != null) ? RunspaceFactory.CreateRunspace(remoteHost) : RunspaceFactory.CreateRunspace();