The Labs \ Source Viewer \ SSCLI \ System.Security \ WindowsImpersonationFlowMode

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. /*============================================================
  15. **
  16. ** Class:  SecurityContext
  17. **
  18. **
  19. ** Purpose: Capture security  context for a thread
  20. **
  21. **
  22. ===========================================================*/
  23. namespace System.Security
  24. {
  25.     using Microsoft.Win32;
  26.     using Microsoft.Win32.SafeHandles;
  27.     using System.Threading;
  28.     using System.Runtime.Remoting;
  29.     using System.Security.Principal;
  30.     using System.Collections;
  31.     using System.Runtime.Serialization;
  32.     using System.Security.Permissions;
  33.     using System.Runtime.InteropServices;
  34.     using System.Runtime.CompilerServices;
  35.     using System.Runtime.ConstrainedExecution;
  36.     using System.Runtime.Versioning;
  37.    
  38.     internal enum SecurityContextDisableFlow
  39.     {
  40.         Nothing = 0,
  41.         WI = 1,
  42.         All = 16383
  43.     }
  44.    
  45.     internal enum WindowsImpersonationFlowMode
  46.     {
  47.         IMP_FASTFLOW = 0,
  48.         IMP_NOFLOW = 1,
  49.         IMP_ALWAYSFLOW = 2,
  50.         IMP_DEFAULT = IMP_FASTFLOW
  51.     }
  52.    
  53.    
  54.     internal struct SecurityContextSwitcher : IDisposable
  55.     {
  56.         internal SecurityContext prevSC;
  57.         // prev SC that we restore on an Undo
  58.         internal SecurityContext currSC;
  59.         //current SC - SetSecurityContext that created the switcher set this on the Thread
  60.         internal ExecutionContext currEC;
  61.         // current ExecutionContext on Thread
  62.         internal CompressedStackSwitcher cssw;
  63.        
  64.         public override bool Equals(object obj)
  65.         {
  66.             if (obj == null || !(obj is SecurityContextSwitcher))
  67.                 return false;
  68.             SecurityContextSwitcher sw = (SecurityContextSwitcher)obj;
  69.             return (this.prevSC == sw.prevSC && this.currSC == sw.currSC && this.currEC == sw.currEC && this.cssw == sw.cssw);
  70.            
  71.         }
  72.        
  73.         public override int GetHashCode()
  74.         {
  75.             return ToString().GetHashCode();
  76.         }
  77.        
  78.         public static bool operator ==(SecurityContextSwitcher c1, SecurityContextSwitcher c2)
  79.         {
  80.             return c1.Equals(c2);
  81.         }
  82.        
  83.         public static bool operator !=(SecurityContextSwitcher c1, SecurityContextSwitcher c2)
  84.         {
  85.             return !c1.Equals(c2);
  86.         }
  87.        
  88.        
  89.         /// <internalonly/>
  90.         void IDisposable.Dispose()
  91.         {
  92.             Undo();
  93.         }
  94.        
  95.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  96.         internal bool UndoNoThrow()
  97.         {
  98.             try {
  99.                 Undo();
  100.             }
  101.             catch {
  102.                 return false;
  103.             }
  104.             return true;
  105.         }
  106.        
  107.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  108.         public void Undo()
  109.         {
  110.             if (currEC == null) {
  111.                 return;
  112.                 // mutiple Undo()s called on this switcher object
  113.             }
  114.            
  115.             if (currEC != Thread.CurrentThread.GetExecutionContextNoCreate())
  116.                 System.Environment.FailFast(Environment.GetResourceString("InvalidOperation_SwitcherCtxMismatch"));
  117.            
  118.             BCLDebug.Assert(currEC != null, " ExecutionContext can't be null");
  119.             BCLDebug.Assert(currSC != null, " SecurityContext can't be null");
  120.             if (currSC != currEC.SecurityContext) {
  121.                 System.Environment.FailFast(Environment.GetResourceString("InvalidOperation_SwitcherCtxMismatch"));
  122.             }
  123.            
  124.             // restore the saved security context
  125.             currEC.SecurityContext = prevSC;
  126.             currEC = null;
  127.             // this will prevent the switcher object being used again
  128.             bool bNoException = true;
  129.             bNoException &= cssw.UndoNoThrow();
  130.            
  131.            
  132.             if (!bNoException) {
  133.                 // Failfast since we can't continue safely...
  134.                 System.Environment.FailFast(Environment.GetResourceString("ExecutionContext_UndoFailed"));
  135.             }
  136.            
  137.         }
  138.     }
  139.    
  140.    
  141.     public sealed class SecurityContext
  142.     {
  143.         // Note that only one of the following variables will be true. The way we set up the flow mode in the g_pConfig guarantees this.
  144.         static bool _LegacyImpersonationPolicy = (GetImpersonationFlowMode() == WindowsImpersonationFlowMode.IMP_NOFLOW);
  145.         static bool _alwaysFlowImpersonationPolicy = (GetImpersonationFlowMode() == WindowsImpersonationFlowMode.IMP_ALWAYSFLOW);
  146.        
  147. /*=========================================================================
  148.         ** Data accessed from managed code that needs to be defined in
  149.         ** SecurityContextObject  to maintain alignment between the two classes.
  150.         ** DON'T CHANGE THESE UNLESS YOU MODIFY SecurityContextObject in vm\object.h
  151.         =========================================================================*/       
  152.        
  153.         private ExecutionContext _executionContext;
  154.         private CompressedStack _compressedStack;
  155.         private static SecurityContext _fullTrustSC;
  156.        
  157.         internal bool isNewCapture = false;
  158.         internal SecurityContextDisableFlow _disableFlow = SecurityContextDisableFlow.Nothing;
  159.        
  160.        
  161.        
  162.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  163.         internal SecurityContext()
  164.         {
  165.         }
  166.        
  167.         static internal SecurityContext FullTrustSecurityContext {
  168.             get {
  169.                 if (_fullTrustSC == null)
  170.                     _fullTrustSC = CreateFullTrustSecurityContext();
  171.                 return _fullTrustSC;
  172.             }
  173.         }
  174.        
  175.         // link the security context to an ExecutionContext
  176.         internal ExecutionContext ExecutionContext {
  177.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  178.             set { _executionContext = value; }
  179.         }
  180.        
  181.        
  182.        
  183.         internal CompressedStack CompressedStack {
  184.             get { return _compressedStack; }
  185.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  186.             set { _compressedStack = value; }
  187.         }
  188.        
  189.        
  190.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  191.         public static AsyncFlowControl SuppressFlow()
  192.         {
  193.             return SuppressFlow(SecurityContextDisableFlow.All);
  194.         }
  195.        
  196.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  197.         public static AsyncFlowControl SuppressFlowWindowsIdentity()
  198.         {
  199.             return SuppressFlow(SecurityContextDisableFlow.WI);
  200.         }
  201.        
  202.         static internal AsyncFlowControl SuppressFlow(SecurityContextDisableFlow flags)
  203.         {
  204.             if (IsFlowSuppressed(flags)) {
  205.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
  206.             }
  207.            
  208.             if (Thread.CurrentThread.ExecutionContext.SecurityContext == null)
  209.                 Thread.CurrentThread.ExecutionContext.SecurityContext = new SecurityContext();
  210.             AsyncFlowControl afc = new AsyncFlowControl();
  211.             afc.Setup(flags);
  212.             return afc;
  213.         }
  214.        
  215.         public static void RestoreFlow()
  216.         {
  217.             SecurityContext sc = GetCurrentSecurityContextNoCreate();
  218.             if (sc == null || sc._disableFlow == SecurityContextDisableFlow.Nothing) {
  219.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
  220.             }
  221.             sc._disableFlow = SecurityContextDisableFlow.Nothing;
  222.         }
  223.        
  224.         public static bool IsFlowSuppressed()
  225.         {
  226.             return SecurityContext.IsFlowSuppressed(SecurityContextDisableFlow.All);
  227.         }
  228.        
  229.         public static bool IsWindowsIdentityFlowSuppressed()
  230.         {
  231.             return (_LegacyImpersonationPolicy || SecurityContext.IsFlowSuppressed(SecurityContextDisableFlow.WI));
  232.         }
  233.        
  234.         static internal bool IsFlowSuppressed(SecurityContextDisableFlow flags)
  235.         {
  236.             SecurityContext sc = GetCurrentSecurityContextNoCreate();
  237.             return (sc == null) ? false : ((sc._disableFlow & flags) == flags);
  238.         }
  239.        
  240.        
  241.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure), DynamicSecurityMethodAttribute()]
  242.         public static void Run(SecurityContext securityContext, ContextCallback callback, object state)
  243.         {
  244.             if (securityContext == null) {
  245.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
  246.             }
  247.            
  248.             if (!securityContext.isNewCapture) {
  249.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
  250.             }
  251.            
  252.             securityContext.isNewCapture = false;
  253.            
  254.             ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate();
  255.             if (SecurityContext.CurrentlyInDefaultFTSecurityContext(ec) && securityContext.IsDefaultFTSecurityContext()) {
  256.                 callback(state);
  257.             }
  258.             else {
  259.                 RunInternal(securityContext, callback, state);
  260.             }
  261.            
  262.         }
  263.         static internal void RunInternal(SecurityContext securityContext, ContextCallback callBack, object state)
  264.         {
  265.             if (cleanupCode == null) {
  266.                 tryCode = new RuntimeHelpers.TryCode(runTryCode);
  267.                 cleanupCode = new RuntimeHelpers.CleanupCode(runFinallyCode);
  268.             }
  269.             SecurityContextRunData runData = new SecurityContextRunData(securityContext, callBack, state);
  270.             RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, runData);
  271.            
  272.         }
  273.        
  274.         internal class SecurityContextRunData
  275.         {
  276.             internal SecurityContext sc;
  277.             internal ContextCallback callBack;
  278.             internal object state;
  279.             internal SecurityContextSwitcher scsw;
  280.             internal SecurityContextRunData(SecurityContext securityContext, ContextCallback cb, object state)
  281.             {
  282.                 this.sc = securityContext;
  283.                 this.callBack = cb;
  284.                 this.state = state;
  285.                 this.scsw = new SecurityContextSwitcher();
  286.             }
  287.         }
  288.        
  289.         [ResourceExposure(ResourceScope.Process)]
  290.         [ResourceConsumption(ResourceScope.Process)]
  291.         static internal void runTryCode(object userData)
  292.         {
  293.             SecurityContextRunData rData = (SecurityContextRunData)userData;
  294.             rData.scsw = SetSecurityContext(rData.sc, Thread.CurrentThread.ExecutionContext.SecurityContext);
  295.             rData.callBack(rData.state);
  296.            
  297.         }
  298.        
  299.         [PrePrepareMethod()]
  300.         static internal void runFinallyCode(object userData, bool exceptionThrown)
  301.         {
  302.             SecurityContextRunData rData = (SecurityContextRunData)userData;
  303.             rData.scsw.Undo();
  304.         }
  305.        
  306.         static internal RuntimeHelpers.TryCode tryCode;
  307.         static internal RuntimeHelpers.CleanupCode cleanupCode;
  308.        
  309.        
  310.        
  311.         // Internal API that gets called from public SetSecurityContext and from SetExecutionContext
  312.         [ResourceExposure(ResourceScope.Process)]
  313.         [ResourceConsumption(ResourceScope.Process)]
  314.         [DynamicSecurityMethodAttribute()]
  315.         static internal SecurityContextSwitcher SetSecurityContext(SecurityContext sc, SecurityContext prevSecurityContext)
  316.         {
  317.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  318.             return SetSecurityContext(sc, prevSecurityContext, ref stackMark);
  319.         }
  320.        
  321.         static internal SecurityContextSwitcher SetSecurityContext(SecurityContext sc, SecurityContext prevSecurityContext, ref StackCrawlMark stackMark)
  322.         {
  323.            
  324.            
  325.             // Save the flow state at capture and reset it in the SC.
  326.             SecurityContextDisableFlow _capturedFlowState = sc._disableFlow;
  327.             sc._disableFlow = SecurityContextDisableFlow.Nothing;
  328.            
  329.             //Set up the switcher object
  330.             SecurityContextSwitcher scsw = new SecurityContextSwitcher();
  331.             scsw.currSC = sc;
  332.             // save the current Execution Context
  333.             ExecutionContext currEC = Thread.CurrentThread.ExecutionContext;
  334.             scsw.currEC = currEC;
  335.             // save the prev security context
  336.             scsw.prevSC = prevSecurityContext;
  337.            
  338.             // update the current security context to the new security context
  339.             currEC.SecurityContext = sc;
  340.            
  341.            
  342.             if (sc != null) {
  343.                 RuntimeHelpers.PrepareConstrainedRegions();
  344.                 try {
  345.                     scsw.cssw = CompressedStack.SetCompressedStack(sc.CompressedStack, (prevSecurityContext != null ? prevSecurityContext.CompressedStack : null));
  346.                 }
  347.                 catch {
  348.                     scsw.UndoNoThrow();
  349.                     throw;
  350.                 }
  351.             }
  352.             return scsw;
  353.         }
  354.        
  355.         /// <internalonly/>
  356.         public SecurityContext CreateCopy()
  357.         {
  358.             if (!isNewCapture) {
  359.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
  360.             }
  361.            
  362.             SecurityContext sc = new SecurityContext();
  363.             sc.isNewCapture = true;
  364.             sc._disableFlow = _disableFlow;
  365.            
  366.            
  367.             if (_compressedStack != null)
  368.                 sc._compressedStack = _compressedStack.CreateCopy();
  369.            
  370.             return sc;
  371.         }
  372.        
  373.        
  374.         public static SecurityContext Capture()
  375.         {
  376.             // check to see if Flow is suppressed or Security is off
  377.             if (IsFlowSuppressed() || !SecurityManager._IsSecurityOn())
  378.                 return null;
  379.            
  380.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  381.             SecurityContext sc = SecurityContext.Capture(Thread.CurrentThread.GetExecutionContextNoCreate(), ref stackMark);
  382.             if (sc == null)
  383.                 sc = CreateFullTrustSecurityContext();
  384.             return sc;
  385.         }
  386.        
  387.         // create a clone from a non-existing SecurityContext
  388.         static internal SecurityContext Capture(ExecutionContext currThreadEC, ref StackCrawlMark stackMark)
  389.         {
  390.             // check to see if Flow is suppressed or Security is off
  391.             if (IsFlowSuppressed() || !SecurityManager._IsSecurityOn())
  392.                 return null;
  393.            
  394.             // If we're in FT right now, return null
  395.             if (CurrentlyInDefaultFTSecurityContext(currThreadEC))
  396.                 return null;
  397.            
  398.             SecurityContext sc = new SecurityContext();
  399.             sc.isNewCapture = true;
  400.            
  401.            
  402.             // Force create CompressedStack
  403.             sc.CompressedStack = CompressedStack.GetCompressedStack(ref stackMark);
  404.             return sc;
  405.         }
  406.         static internal SecurityContext CreateFullTrustSecurityContext()
  407.         {
  408.             SecurityContext sc = new SecurityContext();
  409.             sc.isNewCapture = true;
  410.            
  411.            
  412.            
  413.             // Force create CompressedStack
  414.             sc.CompressedStack = new CompressedStack(null);
  415.             return sc;
  416.         }
  417.         // Check to see if we have a security context and return if we do
  418.         static internal SecurityContext GetCurrentSecurityContextNoCreate()
  419.         {
  420.             ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate();
  421.             return (ec == null) ? null : ec.SecurityContext;
  422.         }
  423.        
  424.         internal bool IsDefaultFTSecurityContext()
  425.         {
  426.             return (CompressedStack == null || CompressedStack.CompressedStackHandle == null);
  427.         }
  428.         static internal bool CurrentlyInDefaultFTSecurityContext(ExecutionContext threadEC)
  429.         {
  430.             return (IsDefaultThreadSecurityInfo());
  431.         }
  432.         [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  433.         static internal extern WindowsImpersonationFlowMode GetImpersonationFlowMode();
  434.         [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  435.         static internal extern bool IsDefaultThreadSecurityInfo();
  436.        
  437.     }
  438. }

Developer Fusion