WindowsIdentity.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / clr / src / BCL / System / Security / Principal / WindowsIdentity.cs / 3 / WindowsIdentity.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// WindowsIdentity.cs 
//
// Representation of a process/thread token. 
//

namespace System.Security.Principal
{ 
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles; 
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices; 
    using System.Runtime.Serialization;
    using System.Security.AccessControl;
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;
    using System.Runtime.Versioning; 
 
    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)] 
    public enum WindowsAccountType {
        Normal      = 0,
        Guest       = 1,
        System      = 2, 
        Anonymous   = 3
    } 
 
    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)] 
    public enum TokenImpersonationLevel {
        None            = 0,
        Anonymous       = 1,
        Identification  = 2, 
        Impersonation   = 3,
        Delegation      = 4 
    } 

    [Serializable, Flags] 
    [System.Runtime.InteropServices.ComVisible(true)]
    public enum TokenAccessLevels {
        AssignPrimary       = 0x00000001,
        Duplicate           = 0x00000002, 
        Impersonate         = 0x00000004,
        Query               = 0x00000008, 
        QuerySource         = 0x00000010, 
        AdjustPrivileges    = 0x00000020,
        AdjustGroups        = 0x00000040, 
        AdjustDefault       = 0x00000080,
        AdjustSessionId     = 0x00000100,

        Read                = 0x00020000 | Query, 

        Write               = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault, 
 
        AllAccess           = 0x000F0000       |
                              AssignPrimary    | 
                              Duplicate        |
                              Impersonate      |
                              Query            |
                              QuerySource      | 
                              AdjustPrivileges |
                              AdjustGroups     | 
                              AdjustDefault    | 
                              AdjustSessionId,
 
        MaximumAllowed      = 0x02000000
    }

    // Keep in sync with vm\comprincipal.h 
    internal enum WinSecurityContext {
        Thread = 1, // OpenAsSelf = false 
        Process = 2, // OpenAsSelf = true 
        Both = 3 // OpenAsSelf = true, then OpenAsSelf = false
    } 

    [Serializable()]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class WindowsIdentity : IIdentity, ISerializable, IDeserializationCallback, IDisposable { 
        private string m_name = null;
        private SecurityIdentifier m_owner = null; 
        private SecurityIdentifier m_user = null; 
        private object m_groups = null;
        private SafeTokenHandle m_safeTokenHandle = SafeTokenHandle.InvalidHandle; 
        private string m_authType = null;
        private int m_isAuthenticated = -1;

        // 
        // Constructors.
        // 
 
        private WindowsIdentity () {}
        internal WindowsIdentity (SafeTokenHandle safeTokenHandle) : this (safeTokenHandle.DangerousGetHandle()) { 
            GC.KeepAlive(safeTokenHandle);
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public WindowsIdentity (IntPtr userToken) : this (userToken, null, -1) {} 
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public WindowsIdentity (IntPtr userToken, string type) : this (userToken, type, -1) {}

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType) : this (userToken, type, -1) {}
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) 
            : this (userToken, type, isAuthenticated ? 1 : 0) {}

        private WindowsIdentity (IntPtr userToken, string authType, int isAuthenticated) {
            CreateFromToken(userToken); 
            m_authType = authType;
            m_isAuthenticated = isAuthenticated; 
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        private void CreateFromToken (IntPtr userToken) {
            if (userToken == IntPtr.Zero)
                throw new ArgumentException(Environment.GetResourceString("Argument_TokenZero")); 

            // Find out if the specified token is a valid. 
            uint dwLength = (uint) Marshal.SizeOf(typeof(uint)); 
            bool result = Win32Native.GetTokenInformation(userToken, (uint) TokenInformationClass.TokenType,
                                                          SafeLocalAllocHandle.InvalidHandle, 0, out dwLength); 
            if (Marshal.GetLastWin32Error() == Win32Native.ERROR_INVALID_HANDLE)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));

            if (!Win32Native.DuplicateHandle(Win32Native.GetCurrentProcess(), 
                                             userToken,
                                             Win32Native.GetCurrentProcess(), 
                                             ref m_safeTokenHandle, 
                                             0,
                                             true, 
                                             Win32Native.DUPLICATE_SAME_ACCESS))
                throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        public WindowsIdentity (string sUserPrincipalName) : this (sUserPrincipalName, null) {} 
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        public WindowsIdentity (string sUserPrincipalName, string type) { 
            m_safeTokenHandle = KerbS4ULogon(sUserPrincipalName);
        }

        // 
        // We cannot make sure the token will stay alive
        // until it is being deserialized in another AppDomain. We do not have a way to capture 
        // the state of a token (just a pointer to kernel memory) and re-construct it later 
        // and even if we did (via calling NtQueryInformationToken and relying on the token undocumented
        // format), constructing a token requires TCB privilege. We need to address the "serializable" 
        // nature of WindowsIdentity since it is not obvious that can be achieved at all.
        //

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        public WindowsIdentity (SerializationInfo info, StreamingContext context) : this(info)
        { 
        } 

        // This is a copy of the serialization constructor above but without the 
        // security demand that's slow and breaks partial trust scenarios
        // without an expensive assertt in place in the remoting code. Instead we
        // special case this class and call the private constructor directly
        // (changing the demand above is considered a breaking change, even 
        // though nobody else should have been using a serialization constructor
        // directly). 
        private WindowsIdentity(SerializationInfo info) { 
            IntPtr userToken = (IntPtr) info.GetValue("m_userToken", typeof(IntPtr));
            if (userToken != IntPtr.Zero) 
                CreateFromToken(userToken);
        }

        ///  
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) { 
            info.AddValue("m_userToken", m_safeTokenHandle.DangerousGetHandle()); 
        }
 
        /// 
        void IDeserializationCallback.OnDeserialization (Object sender) {}

        // 
        // Factory methods.
        // 
 

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        public static WindowsIdentity GetCurrent () {
           return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        public static WindowsIdentity GetCurrent (bool ifImpersonating) { 
           return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, ifImpersonating); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess) {
           return GetCurrentInternal(desiredAccess, false);
        } 

        // GetAnonymous() is used heavily in ASP.NET requests as a dummy identity to indicate 
        // the request is anonymous. It does not represent a real process or thread token so 
        // it cannot impersonate or do anything useful. Note this identity does not represent the
        // usual concept of an anonymous token, and the name is simply misleading but we cannot change it now. 

        public static WindowsIdentity GetAnonymous () {
            return new WindowsIdentity();
        } 

        // 
        // Properties. 
        //
 
        public string AuthenticationType {
            get {
                // If this is an anonymous identity, return an empty string
                if (m_safeTokenHandle.IsInvalid) 
                    return String.Empty;
 
                if (m_authType == null) { 
                    Win32Native.LUID authId = GetLogonAuthId(m_safeTokenHandle);
                    if (authId.LowPart == Win32Native.ANONYMOUS_LOGON_LUID) 
                        return String.Empty; // no authentication, just return an empty string

                    SafeLsaReturnBufferHandle ppLogonSessionData = SafeLsaReturnBufferHandle.InvalidHandle;
                    int status = Win32Native.LsaGetLogonSessionData(ref authId, ref ppLogonSessionData); 
                    if (status < 0) // non-negative numbers indicate success
                        throw GetExceptionFromNtStatus(status); 
 
                    Win32Native.SECURITY_LOGON_SESSION_DATA logonSessionData = (Win32Native.SECURITY_LOGON_SESSION_DATA) Marshal.PtrToStructure(ppLogonSessionData.DangerousGetHandle(), typeof(Win32Native.SECURITY_LOGON_SESSION_DATA));
                    string authPackage = Marshal.PtrToStringUni(logonSessionData.AuthenticationPackage.Buffer); 
                    ppLogonSessionData.Dispose();
                    return authPackage;
                }
 
                return m_authType;
            } 
        } 

 
        [ComVisible(false)]
        public TokenImpersonationLevel ImpersonationLevel {
            get {
                // If this is an anonymous identity 
                if (m_safeTokenHandle.IsInvalid)
                    return TokenImpersonationLevel.Anonymous; 
 
                uint cbSize = 0;
                SafeLocalAllocHandle pTokenType = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenType, out cbSize); 
                int level = Marshal.ReadInt32(pTokenType.DangerousGetHandle());
                if (level == (int) TokenType.TokenPrimary)
                    return TokenImpersonationLevel.None; // primary token
 
                // This is an impersonation token, get the impersonation level
                SafeLocalAllocHandle pImpersonationLevel = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenImpersonationLevel, out cbSize); 
                level = Marshal.ReadInt32(pImpersonationLevel.DangerousGetHandle()); 

                pTokenType.Dispose(); 
                pImpersonationLevel.Dispose();

                return (TokenImpersonationLevel) level + 1;
            } 
        }
 
        public virtual bool IsAuthenticated { 
            get {
                // make this a no-op on Win98 so calling code does not have to special case down-level platforms. 
                if (!RunningOnWin2K)
                    return false;

                if (m_isAuthenticated == -1) { 
                    // There is a known
 
                    WindowsPrincipal wp = new WindowsPrincipal(this); 
                    SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
                                                                    new int[] {Win32Native.SECURITY_AUTHENTICATED_USER_RID}); 
                    m_isAuthenticated = wp.IsInRole(sid) ? 1 : 0;
                }

                return m_isAuthenticated == 1; 
            }
        } 
 
        //
        // IsGuest, IsSystem and IsAnonymous are maintained for compatibility reasons. It is always 
        // possible to extract this same information from the User SID property and the new
        // (and more general) methods defined in the SID class (IsWellKnown, etc...).
        //
 
        public virtual bool IsGuest {
            get { 
                // special case the anonymous identity. 
                if (m_safeTokenHandle.IsInvalid)
                    return false; 
                SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
                                                                new int[] {Win32Native.SECURITY_BUILTIN_DOMAIN_RID, Win32Native.DOMAIN_USER_RID_GUEST});
                return (this.User == sid);
            } 
        }
 
        public virtual bool IsSystem { 
            get {
                // special case the anonymous identity. 
                if (m_safeTokenHandle.IsInvalid)
                    return false;
                SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
                                                                new int[] {Win32Native.SECURITY_LOCAL_SYSTEM_RID}); 
                return (this.User == sid);
            } 
        } 

        public virtual bool IsAnonymous { 
            get {
                // special case the anonymous identity.
                if (m_safeTokenHandle.IsInvalid)
                    return true; 
                SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
                                                                new int[] {Win32Native.SECURITY_ANONYMOUS_LOGON_RID}); 
                return (this.User == sid); 
            }
        } 


        public virtual string Name {
            get { 
                return GetName();
            } 
        } 

        [DynamicSecurityMethodAttribute()] 
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        internal String GetName()
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; 
            // special case the anonymous identity.
            if (m_safeTokenHandle.IsInvalid) 
                return String.Empty; 

            if (m_name == null) 
            {
                // revert thread impersonation for the duration of the call to get the name.
                using (SafeImpersonate(SafeTokenHandle.InvalidHandle, null, ref stackMark))
                { 
                    NTAccount ntAccount = this.User.Translate(typeof(NTAccount)) as NTAccount;
                    m_name = ntAccount.ToString(); 
                } 
            }
 
            return m_name;
        }

        [ComVisible(false)] 
        public SecurityIdentifier Owner {
            get { 
                // special case the anonymous identity. 
                if (m_safeTokenHandle.IsInvalid)
                    return null; 

                if (m_owner == null) {
                    uint cbSize = 0;
                    SafeLocalAllocHandle pOwnerToken = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenOwner, out cbSize); 
                    m_owner = new SecurityIdentifier(Marshal.ReadIntPtr(pOwnerToken.DangerousGetHandle()), true );
                    pOwnerToken.Dispose(); 
                } 

                return m_owner; 
            }
        }

        [ComVisible(false)] 
        public SecurityIdentifier User {
            get { 
                // special case the anonymous identity. 
                if (m_safeTokenHandle.IsInvalid)
                    return null; 

                if (m_user == null) {
                    uint cbSize = 0;
                    SafeLocalAllocHandle pUserToken = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser, out cbSize); 
                    m_user = new SecurityIdentifier(Marshal.ReadIntPtr(pUserToken.DangerousGetHandle()), true );
                    pUserToken.Dispose(); 
                } 

                return m_user; 
            }
        }

        public IdentityReferenceCollection Groups { 
            get {
                // special case the anonymous identity. 
                if (m_safeTokenHandle.IsInvalid) 
                    return null;
 
                if (m_groups == null) {
                    IdentityReferenceCollection groups = new IdentityReferenceCollection();
                    uint cbSize = 0;
                    using (SafeLocalAllocHandle pGroups = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups, out cbSize)) { 
                        int count = Marshal.ReadInt32(pGroups.DangerousGetHandle());
                        IntPtr pSidAndAttributes = new IntPtr((long) pGroups.DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups")); 
                        for (int i = 0; i < count; ++i) { 
                            Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES) Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
                            // Ignore disabled, logon ID, and deny-only groups. 
                            uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
                            if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED) {
                                groups.Add(new SecurityIdentifier(group.Sid, true ));
                            } 
                            pSidAndAttributes = new IntPtr((long) pSidAndAttributes + (long) Marshal.SizeOf(typeof(Win32Native.SID_AND_ATTRIBUTES)));
                        } 
                    } 
                    Interlocked.CompareExchange(ref m_groups, groups, null);
                } 

                return m_groups as IdentityReferenceCollection;
            }
        } 

        // 
        // Note this property does not duplicate the token. This is also the same as V1/Everett behaviour. 
        //
 
        public virtual IntPtr Token {
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                return m_safeTokenHandle.DangerousGetHandle(); 
            }
        } 
 
        //
        // Public methods. 
        //
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public virtual WindowsImpersonationContext Impersonate () 
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; 
            return Impersonate(ref stackMark); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static WindowsImpersonationContext Impersonate (IntPtr userToken) 
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; 
            if (userToken == IntPtr.Zero) 
                return SafeImpersonate(SafeTokenHandle.InvalidHandle, null, ref stackMark);
 
            WindowsIdentity wi = new WindowsIdentity(userToken);
            return wi.Impersonate(ref stackMark);
        }
 
        internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
            // make this a no-op on Win98 so calling code does not have to special case down-level platforms. 
            if (!RunningOnWin2K) 
                return new WindowsImpersonationContext(SafeTokenHandle.InvalidHandle, GetCurrentThreadWI(), false, null);
 
            if (m_safeTokenHandle.IsInvalid)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));

            return SafeImpersonate(m_safeTokenHandle, this, ref stackMark); 
        }
 
        [ComVisible(false)] 
        protected virtual void Dispose(bool disposing) {
            if (disposing) { 
                if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
                    m_safeTokenHandle.Dispose();
            }
            m_name = null; 
            m_owner = null;
            m_user = null; 
        } 

        [ComVisible(false)] 
        public void Dispose() {
            Dispose(true);
        }
 
        //
        // internal. 
        // 

        internal SafeTokenHandle TokenHandle { 
            get {
                return m_safeTokenHandle;
            }
        } 

        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)] 
        internal static WindowsImpersonationContext SafeImpersonate (SafeTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark)
        { 
            // make this a no-op on Win98 so calling code does not have to special case down-level platforms.
            if (!RunningOnWin2K)
                return new WindowsImpersonationContext(SafeTokenHandle.InvalidHandle, GetCurrentThreadWI(), false, null);
 
            bool isImpersonating;
            int hr = 0; 
            SafeTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr); 
            if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
                throw new SecurityException(Win32Native.GetMessage(hr)); 

            // Set the SafeTokenHandle on the FSD:
            FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
            if (secObj == null) 
            {
                if (SecurityManager._IsSecurityOn()) 
                    // Security: REQ_SQ flag is missing. Bad compiler ? 
                    // This can happen when you create delegates over functions that need the REQ_SQ
                    throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) ); 
            }

            WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
 
            if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
                hr = Win32.RevertToSelf(); 
                if (hr < 0) 
                    throw new SecurityException(Win32Native.GetMessage(hr));
                // update identity on the thread 
                UpdateThreadWI(wi);
                secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle));
            } else {
                hr = Win32.RevertToSelf(); 
                if (hr < 0)
                    throw new SecurityException(Win32Native.GetMessage(hr)); 
                hr = Win32.ImpersonateLoggedOnUser(userToken); 
                if (hr < 0) {
                    context.Undo(); 
                    throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
                }
                UpdateThreadWI(wi);
                secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle)); 
            }
 
            return context; 
        }
 
        internal static WindowsIdentity GetCurrentThreadWI()
        {
            return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextNoCreate());
        } 

        internal static void UpdateThreadWI(WindowsIdentity wi) 
        { 
            // Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
            SecurityContext sc = SecurityContext.GetCurrentSecurityContextNoCreate(); 
            if (wi != null && sc == null) {
                // create a new security context on the thread
                sc = new SecurityContext();
                Thread.CurrentThread.ExecutionContext.SecurityContext = sc; 
            }
 
            if (sc != null) // null- 
            {
                sc.WindowsIdentity = wi; 
            }
        }

 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) { 
            WindowsIdentity wi = null;
            if (!RunningOnWin2K) { 
                if (!threadOnly) {
                    // Force create an empty WI
                    wi = new WindowsIdentity();
                    wi.m_name = String.Empty; 
                }
                return wi; // We only do this for backward compatibility. Ideally, we would like to 
                           // throw a NotSupportedException on Win9X platforms. 
            }
 
            int hr = 0;
            bool isImpersonating;
            SafeTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
            if (safeTokenHandle == null || safeTokenHandle.IsInvalid) { 
                // either we wanted only ThreadToken - return null
                if (threadOnly && !isImpersonating) 
                    return wi; 
                // or there was an error
                throw new SecurityException(Win32Native.GetMessage(hr)); 
            }
            wi = new WindowsIdentity();
            wi.m_safeTokenHandle = safeTokenHandle;
            return wi; 
        }
 
        // 
        // private.
        // 

        private static int s_runningOnWin2K = -1;
        internal static bool RunningOnWin2K {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
            get {
                if (s_runningOnWin2K == -1) { 
                    Win32Native.OSVERSIONINFO osvi = new Win32Native.OSVERSIONINFO(); 
                    bool r = Win32Native.GetVersionEx(osvi);
                    s_runningOnWin2K = (r && (osvi.PlatformId == Win32Native.VER_PLATFORM_WIN32_NT) && (osvi.MajorVersion >= 5)) ? 1 : 0; 
                }
                return s_runningOnWin2K == 1;
            }
        } 

        private static int GetHRForWin32Error (int dwLastError) { 
            if ((dwLastError & 0x80000000) == 0x80000000) 
                return dwLastError;
            else 
                return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
        }

        private static Exception GetExceptionFromNtStatus (int status) { 
            if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
                return new UnauthorizedAccessException(); 
 
            if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
                return new OutOfMemoryException(); 

            int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
            return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        private static SafeTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
            BCLDebug.Assert(RunningOnWin2K, "Don't call WindowsIdentity.GetCurrentToken on Win9X"); 

            isImpersonating = true;
            SafeTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
            if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) { 
                // No impersonation
                isImpersonating = false; 
                if (!threadOnly) 
                    safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
            } 
            return safeTokenHandle;
        }

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        private static SafeTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) { 
            hr = 0; 
            SafeTokenHandle safeTokenHandle = SafeTokenHandle.InvalidHandle;
            if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, ref safeTokenHandle)) 
                hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
            return safeTokenHandle;
        }
 
        internal static SafeTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
            SafeTokenHandle safeTokenHandle; 
            hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle); 
            return safeTokenHandle;
        } 

        private static Win32Native.LUID GetLogonAuthId (SafeTokenHandle safeTokenHandle) {
            uint cbSize = 0;
            SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics, out cbSize); 
            Win32Native.TOKEN_STATISTICS statistics = (Win32Native.TOKEN_STATISTICS) Marshal.PtrToStructure(pStatistics.DangerousGetHandle(), typeof(Win32Native.TOKEN_STATISTICS));
            pStatistics.Dispose(); 
            return statistics.AuthenticationId; 
        }
 
        private static SafeLocalAllocHandle GetTokenInformation (SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, out uint dwLength) {
            SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
            dwLength = (uint) Marshal.SizeOf(typeof(uint));
            bool result = Win32Native.GetTokenInformation(tokenHandle, 
                                                          (uint) tokenInformationClass,
                                                          safeLocalAllocHandle, 
                                                          0, 
                                                          out dwLength);
            int dwErrorCode = Marshal.GetLastWin32Error(); 
            switch (dwErrorCode) {
            case Win32Native.ERROR_BAD_LENGTH:
                // special case for TokenSessionId. Falling through
            case Win32Native.ERROR_INSUFFICIENT_BUFFER: 
                // ptrLength is an [In] param to LocalAlloc
                IntPtr ptrLength = new IntPtr(dwLength); 
                safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength); 
                if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
                    throw new OutOfMemoryException(); 

                result = Win32Native.GetTokenInformation(tokenHandle,
                                                         (uint) tokenInformationClass,
                                                         safeLocalAllocHandle, 
                                                         dwLength,
                                                         out dwLength); 
                if (!result) 
                    throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
                break; 
            case Win32Native.ERROR_INVALID_HANDLE:
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
            default:
                throw new SecurityException(Win32Native.GetMessage(dwErrorCode)); 
            }
            return safeLocalAllocHandle; 
        } 

        private unsafe static SafeTokenHandle KerbS4ULogon (string upn) { 
            // source name
            byte[] sourceName = new byte[] {(byte) 'C', (byte) 'L', (byte) 'R'}; // we set the source name to "CLR".

            // ptrLength is an [In] param to LocalAlloc 
            IntPtr ptrLength = new IntPtr((uint) (sourceName.Length + 1));
 
            SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength); 
            Marshal.Copy(sourceName, 0, pSourceName.DangerousGetHandle(), sourceName.Length);
            Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING (sourceName.Length, sourceName.Length + 1, pSourceName.DangerousGetHandle()); 

            int status;
            SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
 
            Privilege privilege = null;
 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            // Try to get an impersonation token.
            try { 
                // Try to enable the TCB privilege if possible
                try {
                    privilege = new Privilege("SeTcbPrivilege");
                    privilege.Enable(); 
                } catch (PrivilegeNotHeldException) {}
 
                IntPtr dummy = IntPtr.Zero; 
                status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
                if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) { 
                    // We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
                    status = Win32Native.LsaConnectUntrusted(ref logonHandle);
                }
            } 
            catch {
                // protect against exception filter-based luring attacks 
                if (privilege != null) 
                    privilege.Revert();
                throw; 
            }
            finally {
                if (privilege != null)
                    privilege.Revert(); 
            }
            if (status < 0) // non-negative numbers indicate success 
                throw GetExceptionFromNtStatus(status); 

            // package name ("Kerberos") 
            byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
            Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);

            // ptrLength is an [In] param to LocalAlloc 
            ptrLength = new IntPtr((uint) arrayPackageName.Length);
            SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength); 
            if (pPackageName == null || pPackageName.IsInvalid) 
                throw new OutOfMemoryException();
            Marshal.Copy(arrayPackageName, 0, pPackageName.DangerousGetHandle(), arrayPackageName.Length); 
            Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING (Win32Native.MICROSOFT_KERBEROS_NAME.Length, Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1, pPackageName.DangerousGetHandle());

            uint packageId = 0;
            status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId); 
            if (status < 0) // non-negative numbers indicate success
                throw GetExceptionFromNtStatus(status); 
 
            // source context
            Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE(); 
            if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
                throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
            sourceContext.Name = new char[8];
            sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R'; 

            uint profileSize = 0; 
            SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle; 
            Win32Native.LUID logonId = new Win32Native.LUID();
            Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS(); 
            int subStatus = 0;

            SafeTokenHandle safeTokenHandle = SafeTokenHandle.InvalidHandle;
 
            // logon info
            int logonInfoSize = Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + 2 * (upn.Length + 1); 
            byte[] logonInfo = new byte[logonInfoSize]; 
            // We need to protect the byte array so we can pack the KERB_S4U_LOGON safely since
            // LsaLogonUser expects the structure to be serialized. 
            fixed (byte* ptr = logonInfo) {
                byte[] arrayUpnName = new byte[2 * (upn.Length + 1)];
                Encoding.Unicode.GetBytes(upn, 0, upn.Length, arrayUpnName, 0);
                Buffer.BlockCopy(arrayUpnName, 0, logonInfo, Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)), arrayUpnName.Length); 
                Win32Native.KERB_S4U_LOGON * pLogonInfo = (Win32Native.KERB_S4U_LOGON *) ptr;
                pLogonInfo->MessageType = (uint) KerbLogonSubmitType.KerbS4ULogon; 
                pLogonInfo->Flags = 0; 
                pLogonInfo->ClientUpn.Length = (ushort) (2 * upn.Length);
                pLogonInfo->ClientUpn.MaxLength = (ushort) (2 * (upn.Length + 1)); 
                pLogonInfo->ClientUpn.Buffer = new IntPtr((byte*) (pLogonInfo + 1));
                // logon user
                status = Win32Native.LsaLogonUser(logonHandle,
                                                  ref Name, 
                                                  (uint) SecurityLogonType.Network,
                                                  packageId, 
                                                  new IntPtr(ptr), 
                                                  (uint) logonInfo.Length,
                                                  IntPtr.Zero, 
                                                  ref sourceContext,
                                                  ref profile,
                                                  ref profileSize,
                                                  ref logonId, 
                                                  ref safeTokenHandle,
                                                  ref quotas, 
                                                  ref subStatus); 
            }
 
            // If both status and substatus are < 0, substatus is preferred.
            if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
                status = subStatus;
            if (status < 0) // non-negative numbers indicate success 
                throw GetExceptionFromNtStatus(status);
            if (subStatus < 0) // non-negative numbers indicate success 
                throw GetExceptionFromNtStatus(subStatus); 

            profile.Dispose(); 
            pSourceName.Dispose();
            pPackageName.Dispose();
            logonHandle.Dispose();
 
            return safeTokenHandle;
        } 
    } 

    [Serializable] 
    internal enum KerbLogonSubmitType : int {
        KerbInteractiveLogon = 2,
        KerbSmartCardLogon = 6,
        KerbWorkstationUnlockLogon = 7, 
        KerbSmartCardUnlockLogon = 8,
        KerbProxyLogon = 9, 
        KerbTicketLogon = 10, 
        KerbTicketUnlockLogon = 11,
        KerbS4ULogon = 12 
    }

    [Serializable]
    internal enum SecurityLogonType : int { 
        Interactive = 2,
        Network, 
        Batch, 
        Service,
        Proxy, 
        Unlock
    }

    [Serializable] 
    internal enum TokenType : int {
        TokenPrimary = 1, 
        TokenImpersonation 
    }
 
    [Serializable]
    internal enum TokenInformationClass : int {
        TokenUser = 1,
        TokenGroups, 
        TokenPrivileges,
        TokenOwner, 
        TokenPrimaryGroup, 
        TokenDefaultDacl,
        TokenSource, 
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids, 
        TokenSessionId,
        TokenGroupsAndPrivileges, 
        TokenSessionReference, 
        TokenSandBoxInert
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK