File: system\security\principal\win32.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
// 
 
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Runtime.Versioning;
 
namespace System.Security.Principal
{
    using BOOL = System.Int32;
    using DWORD = System.UInt32;
    using System.Globalization;
    using System.Diagnostics.Contracts;
 
    [Flags]
    internal enum PolicyRights
    {
        POLICY_VIEW_LOCAL_INFORMATION            = 0x00000001,
        POLICY_VIEW_AUDIT_INFORMATION            = 0x00000002,
        POLICY_GET_PRIVATE_INFORMATION           = 0x00000004,
        POLICY_TRUST_ADMIN                       = 0x00000008,
        POLICY_CREATE_ACCOUNT                    = 0x00000010,
        POLICY_CREATE_SECRET                     = 0x00000020,
        POLICY_CREATE_PRIVILEGE                  = 0x00000040,
        POLICY_SET_DEFAULT_QUOTA_LIMITS          = 0x00000080,
        POLICY_SET_AUDIT_REQUIREMENTS            = 0x00000100,
        POLICY_AUDIT_LOG_ADMIN                   = 0x00000200,
        POLICY_SERVER_ADMIN                      = 0x00000400,
        POLICY_LOOKUP_NAMES                      = 0x00000800,
        POLICY_NOTIFICATION                      = 0x00001000,
    }
 
    internal static class Win32
    {
        internal const BOOL FALSE = 0;
        internal const BOOL TRUE = 1;
 
        private static bool _LsaLookupNames2Supported;
        private static bool _WellKnownSidApisSupported;
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        static Win32() 
        {
            
            Win32Native.OSVERSIONINFO osvi = new Win32Native.OSVERSIONINFO();
 
            bool r = Environment.GetVersion(osvi);
            if ( !r )
            {
                Contract.Assert( r, "OSVersion native call failed." );
                throw new SystemException( Environment.GetResourceString( "InvalidOperation_GetVersion" ));
            }
                if (osvi.MajorVersion > 5 || osvi.MinorVersion > 0 ) // Windows XP/2003 and above
                {
 
                    //
                    // LsaLookupNames2 supported only on XP and Windows 2003 and above
                    //
                    _LsaLookupNames2Supported = true;
                    _WellKnownSidApisSupported = true;
                }
                else 
                {
                    // Win2000
                    _LsaLookupNames2Supported = false;
                
 
                    //
                    // WellKnownSid apis are only supported on Windows 2000 SP3 and above
                    // (so we need sp info)
                    //
                    Win32Native.OSVERSIONINFOEX osviex = new Win32Native.OSVERSIONINFOEX();
 
                    r = Environment.GetVersionEx(osviex);
                    if ( !r )
                    {
                        Contract.Assert( r, "OSVersion native call failed");
                        throw new SystemException( Environment.GetResourceString( "InvalidOperation_GetVersion" ));
                    }
 
                    if (osviex.ServicePackMajor < 3) 
                    {
                        _WellKnownSidApisSupported = false;    
                    }
                    else 
                    {
                        _WellKnownSidApisSupported = true; 
                    }
                }
            }
 
        internal static bool LsaLookupNames2Supported
        {
            get {
                return _LsaLookupNames2Supported;
            }
        }
 
        internal static bool WellKnownSidApisSupported
        {
            get {
                return _WellKnownSidApisSupported;
            }
        }
 
        //
        // Wrapper around advapi32.LsaOpenPolicy
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static SafeLsaPolicyHandle LsaOpenPolicy(
            string systemName,
            PolicyRights rights )
        {
            uint ReturnCode;
            SafeLsaPolicyHandle Result;
            Win32Native.LSA_OBJECT_ATTRIBUTES Loa;
 
            Loa.Length = Marshal.SizeOf( typeof( Win32Native.LSA_OBJECT_ATTRIBUTES ));
            Loa.RootDirectory = IntPtr.Zero;
            Loa.ObjectName = IntPtr.Zero;
            Loa.Attributes = 0;
            Loa.SecurityDescriptor = IntPtr.Zero;
            Loa.SecurityQualityOfService = IntPtr.Zero;
 
            if ( 0 == ( ReturnCode = Win32Native.LsaOpenPolicy( systemName, ref Loa, ( int )rights, out Result )))
            {
                return Result;
            }
            else if ( ReturnCode == Win32Native.STATUS_ACCESS_DENIED ) 
            {
                throw new UnauthorizedAccessException();
            }
            else if ( ReturnCode == Win32Native.STATUS_INSUFFICIENT_RESOURCES ||
                      ReturnCode == Win32Native.STATUS_NO_MEMORY ) 
            {
                throw new OutOfMemoryException();
            }
            else
            {
                int win32ErrorCode = Win32Native.LsaNtStatusToWinError(unchecked((int) ReturnCode));
                
                throw new SystemException(Win32Native.GetMessage(win32ErrorCode));
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static byte[] ConvertIntPtrSidToByteArraySid( IntPtr binaryForm )
        {
            byte[] ResultSid;
 
            //
            // Verify the revision (just sanity, should never fail to be 1)
            //
 
            byte Revision = Marshal.ReadByte( binaryForm, 0 );
 
            if ( Revision != SecurityIdentifier.Revision )
            {
                throw new ArgumentException(Environment.GetResourceString( "IdentityReference_InvalidSidRevision" ), "binaryForm");
            }
 
            //
            // Need the subauthority count in order to figure out how many bytes to read
            //
 
            byte SubAuthorityCount = Marshal.ReadByte( binaryForm, 1 );
 
            if ( SubAuthorityCount < 0 ||
                SubAuthorityCount > SecurityIdentifier.MaxSubAuthorities )
            {
                throw new ArgumentException(Environment.GetResourceString( "IdentityReference_InvalidNumberOfSubauthorities", SecurityIdentifier.MaxSubAuthorities), "binaryForm");
            }
 
            //
            // Compute the size of the binary form of this SID and allocate the memory
            //
 
            int BinaryLength = 1 + 1 + 6 + SubAuthorityCount * 4;
            ResultSid = new byte[ BinaryLength ];
 
            //
            // Extract the data from the returned pointer
            //
 
            Marshal.Copy( binaryForm, ResultSid, 0, BinaryLength );
 
            return ResultSid;
        }
 
        //
        // Wrapper around advapi32.ConvertStringSidToSidW
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static int CreateSidFromString(
            string stringSid,
            out byte[] resultSid
            )
        {
            int ErrorCode;
            IntPtr ByteArray = IntPtr.Zero;
 
            try
            {
                if ( TRUE != Win32Native.ConvertStringSidToSid( stringSid, out ByteArray ))
                {
                    ErrorCode = Marshal.GetLastWin32Error();
                    goto Error;
                }
 
                resultSid = ConvertIntPtrSidToByteArraySid( ByteArray );
            }
            finally
            {
                //
                // Now is a good time to get rid of the returned pointer
                //
 
                Win32Native.LocalFree( ByteArray );
            }
 
            //
            // Now invoke the SecurityIdentifier factory method to create the result
            //
 
            return Win32Native.ERROR_SUCCESS;
 
        Error:
 
            resultSid = null;
            return ErrorCode;
        }
 
        //
        // Wrapper around advapi32.CreateWellKnownSid
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static int CreateWellKnownSid(
            WellKnownSidType sidType,
            SecurityIdentifier domainSid,
            out byte[] resultSid
            )
        {
 
            //
            // Check if the api is supported
            //
            if (!WellKnownSidApisSupported) {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
            }
        
            //
            // Passing an array as big as it can ever be is a small price to pay for
            // not having to P/Invoke twice (once to get the buffer, once to get the data)
            //
 
            uint length = ( uint )SecurityIdentifier.MaxBinaryLength;
            resultSid = new byte[ length ];
 
            if ( FALSE != Win32Native.CreateWellKnownSid(( int )sidType, domainSid == null ? null : domainSid.BinaryForm, resultSid, ref length ))
            {
                return Win32Native.ERROR_SUCCESS;
            }
            else
            {
                resultSid = null;
 
                return Marshal.GetLastWin32Error();
            }
        }
 
        //
        // Wrapper around advapi32.EqualDomainSid
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool IsEqualDomainSid( SecurityIdentifier sid1, SecurityIdentifier sid2 )
        {
            //
            // Check if the api is supported
            //
            if (!WellKnownSidApisSupported) {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
            }
        
            if ( sid1 == null || sid2 == null )
            {
                return false;
            }
            else
            {
                bool result;
                
                byte[] BinaryForm1 = new Byte[sid1.BinaryLength];
                sid1.GetBinaryForm( BinaryForm1, 0 );
 
                byte[] BinaryForm2 = new Byte[sid2.BinaryLength];
                sid2.GetBinaryForm( BinaryForm2, 0 );
 
                return ( Win32Native.IsEqualDomainSid( BinaryForm1, BinaryForm2, out result ) == FALSE ? false : result );
            }
        }
 
        /// <summary>
        ///     Setup the size of the buffer Windows provides for an LSA_REFERENCED_DOMAIN_LIST
        /// </summary>
        [System.Security.SecurityCritical]  // auto-generated
        internal static void InitializeReferencedDomainsPointer(SafeLsaMemoryHandle referencedDomains)
        {
            Contract.Assert(referencedDomains != null, "referencedDomains != null");
 
            // We don't know the real size of the referenced domains yet, so we need to set an initial
            // size based on the LSA_REFERENCED_DOMAIN_LIST structure, then resize it to include all of
            // the domains.
            referencedDomains.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.LSA_REFERENCED_DOMAIN_LIST)));
            Win32Native.LSA_REFERENCED_DOMAIN_LIST domainList = referencedDomains.Read<Win32Native.LSA_REFERENCED_DOMAIN_LIST>(0);
 
            unsafe
            {
                byte* pRdl = null;
                RuntimeHelpers.PrepareConstrainedRegions();
                try
                {
                    referencedDomains.AcquirePointer(ref pRdl);
 
                    // If there is a trust information list, then the buffer size is the end of that list minus
                    // the beginning of the domain list. Otherwise, then the buffer is just the size of the
                    // referenced domain list structure, which is what we defaulted to.
                    if (!domainList.Domains.IsNull())
                    {
                        Win32Native.LSA_TRUST_INFORMATION* pTrustInformation = (Win32Native.LSA_TRUST_INFORMATION*)domainList.Domains;
                        pTrustInformation = pTrustInformation + domainList.Entries;
 
                        long bufferSize = (byte*)pTrustInformation - pRdl;
                        Contract.Assert(bufferSize > 0, "bufferSize > 0");
                        referencedDomains.Initialize((ulong)bufferSize);
                    }
                }
                finally
                {
                    if (pRdl != null)
                        referencedDomains.ReleasePointer();
                }
            }
        }
 
        //
        // Wrapper around avdapi32.GetWindowsAccountDomainSid
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static int GetWindowsAccountDomainSid(
            SecurityIdentifier sid,
            out SecurityIdentifier resultSid
            )
        {
 
            //
            // Check if the api is supported
            //
            if (!WellKnownSidApisSupported) {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
            }
        
            //
            // Passing an array as big as it can ever be is a small price to pay for
            // not having to P/Invoke twice (once to get the buffer, once to get the data)
            //
 
            byte[] BinaryForm = new Byte[sid.BinaryLength];
            sid.GetBinaryForm( BinaryForm, 0 );
            uint sidLength = ( uint )SecurityIdentifier.MaxBinaryLength;
            byte[] resultSidBinary = new byte[ sidLength ];
 
            if ( FALSE != Win32Native.GetWindowsAccountDomainSid( BinaryForm, resultSidBinary, ref sidLength ))
            {
                resultSid = new SecurityIdentifier( resultSidBinary, 0 );
 
                return Win32Native.ERROR_SUCCESS;
            }
            else
            {
                resultSid = null;
 
                return Marshal.GetLastWin32Error();
            }
        }
 
        //
        // Wrapper around advapi32.IsWellKnownSid
        //
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool IsWellKnownSid(
            SecurityIdentifier sid,
            WellKnownSidType type
            )
        {
            //
            // Check if the api is supported
            //
            if (!WellKnownSidApisSupported) {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
            }
      
            byte[] BinaryForm = new byte[sid.BinaryLength];
            sid.GetBinaryForm( BinaryForm, 0 );
 
            if ( FALSE == Win32Native.IsWellKnownSid( BinaryForm, ( int )type ))
            {
                return false;
            }
            else
            {
                return true;
            }
        }
 
 
        // When the CLR is hosted, the host gets to implement these calls,
        // otherwise, we call down into the Win32 APIs.
 
#if FEATURE_IMPERSONATION
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
        internal static extern int ImpersonateLoggedOnUser (SafeAccessTokenHandle hToken);
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int OpenThreadToken (TokenAccessLevels dwDesiredAccess, WinSecurityContext OpenAs, out SafeAccessTokenHandle phThreadToken);
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
        internal static extern int RevertToSelf ();
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
        internal static extern int SetThreadToken(SafeAccessTokenHandle hToken);
#endif        
    }
}