|
1 | 1 | // Copyright (c) Microsoft Corporation. All rights reserved. |
2 | 2 | // Licensed under the MIT License. |
3 | 3 |
|
4 | | -using System.Diagnostics; |
5 | 4 | using System.Collections.Generic; |
| 5 | +using System.Diagnostics; |
6 | 6 | using System.Globalization; |
7 | | -using System.Threading; |
8 | | -using Microsoft.Win32; |
9 | 7 | using System.Management.Automation.Internal; |
10 | 8 | using System.Management.Automation.Internal.Host; |
11 | 9 | using System.Management.Automation.Tracing; |
| 10 | +#if !UNIX |
| 11 | +using System.Security.Principal; |
| 12 | +#endif |
| 13 | +using System.Threading; |
12 | 14 | using Microsoft.PowerShell.Commands; |
| 15 | +using Microsoft.Win32; |
13 | 16 |
|
14 | 17 | using Dbg = System.Management.Automation.Diagnostics; |
15 | 18 |
|
@@ -152,13 +155,29 @@ protected override void StartPipelineExecution() |
152 | 155 |
|
153 | 156 | PSThreadOptions memberOptions = this.IsNested ? PSThreadOptions.UseCurrentThread : this.LocalRunspace.ThreadOptions; |
154 | 157 |
|
| 158 | +#if !UNIX |
| 159 | + // Use thread proc that supports impersonation flow for new thread start. |
| 160 | + ThreadStart invokeThreadProcDelegate = InvokeThreadProcImpersonate; |
| 161 | + _identityToImpersonate = null; |
| 162 | + |
| 163 | + // If impersonation identity flow is requested, then get current thread impersonation, if any. |
| 164 | + if ((InvocationSettings != null) && InvocationSettings.FlowImpersonationPolicy) |
| 165 | + { |
| 166 | + Utils.TryGetWindowsImpersonatedIdentity(out _identityToImpersonate); |
| 167 | + } |
| 168 | +#else |
| 169 | + // UNIX does not support thread impersonation flow. |
| 170 | + ThreadStart invokeThreadProcDelegate = InvokeThreadProc; |
| 171 | +#endif |
| 172 | + |
155 | 173 | switch (memberOptions) |
156 | 174 | { |
157 | 175 | case PSThreadOptions.Default: |
158 | 176 | case PSThreadOptions.UseNewThread: |
159 | 177 | { |
160 | | - // Start execution of pipeline in another thread |
161 | | - Thread invokeThread = new Thread(new ThreadStart(this.InvokeThreadProc), DefaultPipelineStackSize); |
| 178 | + // Start execution of pipeline in another thread, |
| 179 | + // and support impersonation flow as needed (Windows only). |
| 180 | + Thread invokeThread = new Thread(new ThreadStart(invokeThreadProcDelegate), DefaultPipelineStackSize); |
162 | 181 | SetupInvokeThread(invokeThread, true); |
163 | 182 | #if !CORECLR |
164 | 183 | // No ApartmentState in CoreCLR |
@@ -187,16 +206,18 @@ protected override void StartPipelineExecution() |
187 | 206 | { |
188 | 207 | if (this.IsNested) |
189 | 208 | { |
190 | | - // if this a nested pipeline we are already in the appropriate thread so we just execute the pipeline here |
| 209 | + // If this a nested pipeline we are already in the appropriate thread so we just execute the pipeline here. |
| 210 | + // Impersonation flow (Windows only) is not needed when using existing thread. |
191 | 211 | SetupInvokeThread(Thread.CurrentThread, true); |
192 | | - this.InvokeThreadProc(); |
| 212 | + InvokeThreadProc(); |
193 | 213 | } |
194 | 214 | else |
195 | 215 | { |
196 | | - // otherwise we execute the pipeline in the Runspace's thread |
| 216 | + // Otherwise we execute the pipeline in the Runspace's thread, |
| 217 | + // and support information flow on new thread as needed (Windows only). |
197 | 218 | PipelineThread invokeThread = this.LocalRunspace.GetPipelineThread(); |
198 | 219 | SetupInvokeThread(invokeThread.Worker, true); |
199 | | - invokeThread.Start(this.InvokeThreadProc); |
| 220 | + invokeThread.Start(invokeThreadProcDelegate); |
200 | 221 | } |
201 | 222 | break; |
202 | 223 | } |
@@ -210,9 +231,10 @@ protected override void StartPipelineExecution() |
210 | 231 |
|
211 | 232 | try |
212 | 233 | { |
213 | | - // prepare invoke thread |
| 234 | + // Prepare invoke thread. |
| 235 | + // Impersonation flow (Windows only) is not needed when using existing thread. |
214 | 236 | SetupInvokeThread(Thread.CurrentThread, false); |
215 | | - this.InvokeThreadProc(); |
| 237 | + InvokeThreadProc(); |
216 | 238 | } |
217 | 239 | finally |
218 | 240 | { |
@@ -508,8 +530,26 @@ private FlowControlException InvokeHelper() |
508 | 530 | return flowControlException; |
509 | 531 | } |
510 | 532 |
|
511 | | - // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 |
512 | | - // Removed HandleUnexpectedExceptions infrastructure |
| 533 | +#if !UNIX |
| 534 | + /// <summary> |
| 535 | + /// Invokes the InvokeThreadProc() method on new thread, and flows calling thread |
| 536 | + /// impersonation as needed. |
| 537 | + /// </summary> |
| 538 | + private void InvokeThreadProcImpersonate() |
| 539 | + { |
| 540 | + if (_identityToImpersonate != null) |
| 541 | + { |
| 542 | + WindowsIdentity.RunImpersonated( |
| 543 | + _identityToImpersonate.AccessToken, |
| 544 | + () => InvokeThreadProc()); |
| 545 | + |
| 546 | + return; |
| 547 | + } |
| 548 | + |
| 549 | + InvokeThreadProc(); |
| 550 | + } |
| 551 | +#endif |
| 552 | + |
513 | 553 | /// <summary> |
514 | 554 | /// Start thread method for asynchronous pipeline execution. |
515 | 555 | /// </summary> |
@@ -520,19 +560,6 @@ private void InvokeThreadProc() |
520 | 560 |
|
521 | 561 | try |
522 | 562 | { |
523 | | -#if !CORECLR // Impersonation is not supported in CoreCLR. |
524 | | - // Used to store old impersonation context if we impersonate. |
525 | | - System.Security.Principal.WindowsImpersonationContext oldImpersonationCtxt = null; |
526 | | - try |
527 | | - { |
528 | | - if ((InvocationSettings != null) && (InvocationSettings.FlowImpersonationPolicy)) |
529 | | - { |
530 | | - // we have a valid identity to impersonate. |
531 | | - System.Security.Principal.WindowsIdentity identityToImPersonate = |
532 | | - new System.Security.Principal.WindowsIdentity(InvocationSettings.WindowsIdentityToImpersonate.Token); |
533 | | - oldImpersonationCtxt = identityToImPersonate.Impersonate(); |
534 | | - } |
535 | | -#endif |
536 | 563 | // Set up pipeline internal host if it is available. |
537 | 564 | if (InvocationSettings != null && InvocationSettings.Host != null) |
538 | 565 | { |
@@ -575,29 +602,6 @@ private void InvokeThreadProc() |
575 | 602 | // Invoke finished successfully. Set state to Completed. |
576 | 603 | SetPipelineState(PipelineState.Completed); |
577 | 604 | } |
578 | | -#if !CORECLR |
579 | | - } |
580 | | - finally |
581 | | - { |
582 | | - // Impersonation is not supported in CoreCLR. |
583 | | - // This finally block is needed to handle fxcop CA2124 |
584 | | - // If sensitive operations such as impersonation occur in the try block, and an |
585 | | - // exception is thrown, the filter can execute before the finally block. For the |
586 | | - // impersonation example, this means that the filter would execute as the impersonated user. |
587 | | - if (oldImpersonationCtxt != null) |
588 | | - { |
589 | | - try |
590 | | - { |
591 | | - oldImpersonationCtxt.Undo(); |
592 | | - oldImpersonationCtxt.Dispose(); |
593 | | - oldImpersonationCtxt = null; |
594 | | - } |
595 | | - catch (System.Security.SecurityException) |
596 | | - { |
597 | | - } |
598 | | - } |
599 | | - } |
600 | | -#endif |
601 | 605 | } |
602 | 606 | catch (PipelineStoppedException ex) |
603 | 607 | { |
@@ -1101,12 +1105,15 @@ private LocalRunspace LocalRunspace |
1101 | 1105 | } |
1102 | 1106 | } |
1103 | 1107 |
|
1104 | | - // NTRAID#Windows Out Of Band Releases-925566-2005/12/09-JonN |
1105 | 1108 | private bool _useExternalInput; |
1106 | 1109 |
|
1107 | 1110 | private PipelineWriter _oldExternalErrorOutput; |
1108 | 1111 | private PipelineWriter _oldExternalSuccessOutput; |
1109 | 1112 |
|
| 1113 | +#if !UNIX |
| 1114 | + private WindowsIdentity _identityToImpersonate; |
| 1115 | +#endif |
| 1116 | + |
1110 | 1117 | #endregion private_fields |
1111 | 1118 |
|
1112 | 1119 | #region invoke_loop_detection |
|