| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- //------------------------------------------------------------------------------
- // <copyright file="DbConnectionPoolIdentity.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.ProviderBase {
- using System;
- using System.Collections;
- using System.Data.Common;
- using System.Diagnostics;
- using System.Globalization;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Permissions;
- using System.Security.Principal;
- using System.Threading;
- using System.Runtime.Versioning;
- [Serializable] // Serializable so SqlDependencyProcessDispatcher can marshall cross domain to SqlDependency.
- sealed internal class DbConnectionPoolIdentity {
- private const int E_NotImpersonationToken = unchecked((int)0x8007051D);
- private const int Win32_CheckTokenMembership = 1;
- private const int Win32_GetTokenInformation_1 = 2;
- private const int Win32_GetTokenInformation_2 = 3;
- private const int Win32_ConvertSidToStringSidW = 4;
- private const int Win32_CreateWellKnownSid = 5;
- static public readonly DbConnectionPoolIdentity NoIdentity = new DbConnectionPoolIdentity(String.Empty, false, true);
- static private readonly byte[] NetworkSid = (ADP.IsWindowsNT ? CreateWellKnownSid(WellKnownSidType.NetworkSid) : null);
- static private DbConnectionPoolIdentity _lastIdentity = null;
- private readonly string _sidString;
- private readonly bool _isRestricted;
- private readonly bool _isNetwork;
- private readonly int _hashCode;
- private DbConnectionPoolIdentity (string sidString, bool isRestricted, bool isNetwork) {
- _sidString = sidString;
- _isRestricted = isRestricted;
- _isNetwork = isNetwork;
- _hashCode = sidString == null ? 0 : sidString.GetHashCode();
- }
- internal bool IsRestricted {
- get { return _isRestricted; }
- }
- internal bool IsNetwork {
- get { return _isNetwork; }
- }
- static private byte[] CreateWellKnownSid(WellKnownSidType sidType) {
- // 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;
- byte[] resultSid = new byte[ length ];
- // NOTE - We copied this code from System.Security.Principal.Win32.CreateWellKnownSid...
- if ( 0 == UnsafeNativeMethods.CreateWellKnownSid(( int )sidType, null, resultSid, ref length )) {
- IntegratedSecurityError(Win32_CreateWellKnownSid);
- }
- return resultSid;
- }
- override public bool Equals(object value) {
- bool result = ((this == NoIdentity) || (this == value));
- if (!result && (null != value)) {
- DbConnectionPoolIdentity that = ((DbConnectionPoolIdentity) value);
- result = ((this._sidString == that._sidString) && (this._isRestricted == that._isRestricted) && (this._isNetwork == that._isNetwork));
- }
- return result;
- }
- [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
- static internal WindowsIdentity GetCurrentWindowsIdentity() {
- return WindowsIdentity.GetCurrent();
- }
- [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
- static private IntPtr GetWindowsIdentityToken(WindowsIdentity identity) {
- return identity.Token;
- }
- [ResourceExposure(ResourceScope.None)] // SxS: this method does not create named objects
- [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
- static internal DbConnectionPoolIdentity GetCurrent() {
- // DEVNOTE: GetTokenInfo and EqualSID do not work on 9x. WindowsIdentity does not
- // work either on 9x. In fact, after checking with native there is no way
- // to validate the user on 9x, so simply don't. It is a known issue in
- // native, and we will handle this the same way.
- if (!ADP.IsWindowsNT) {
- return NoIdentity;
- }
- WindowsIdentity identity = GetCurrentWindowsIdentity();
- IntPtr token = GetWindowsIdentityToken(identity); // Free'd by WindowsIdentity.
- uint bufferLength = 2048; // Suggested default given by Greg Fee.
- uint lengthNeeded = 0;
- IntPtr tokenStruct = IntPtr.Zero;
- IntPtr SID;
- IntPtr sidStringBuffer = IntPtr.Zero;
- bool isNetwork;
- // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails
- bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token);
-
- DbConnectionPoolIdentity current = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- if (!UnsafeNativeMethods.CheckTokenMembership(token, NetworkSid, out isNetwork)) {
- // will always fail with 0x8007051D if token is not an impersonation token
- IntegratedSecurityError(Win32_CheckTokenMembership);
- }
-
- RuntimeHelpers.PrepareConstrainedRegions();
- try { } finally {
- // allocating memory and assigning to tokenStruct must happen
- tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength);
- }
- if (IntPtr.Zero == tokenStruct) {
- throw new OutOfMemoryException();
- }
- if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) {
- if (lengthNeeded > bufferLength) {
- bufferLength = lengthNeeded;
- RuntimeHelpers.PrepareConstrainedRegions();
- try { } finally {
- // freeing token struct and setting tokenstruct to null must happen together
- // allocating memory and assigning to tokenStruct must happen
- SafeNativeMethods.LocalFree(tokenStruct);
- tokenStruct = IntPtr.Zero; // protect against LocalAlloc throwing an exception
- tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength);
- }
- if (IntPtr.Zero == tokenStruct) {
- throw new OutOfMemoryException();
- }
- if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) {
- IntegratedSecurityError(Win32_GetTokenInformation_1);
- }
- }
- else {
- IntegratedSecurityError(Win32_GetTokenInformation_2);
- }
- }
- identity.Dispose(); // Keep identity variable alive until after GetTokenInformation calls.
- SID = Marshal.ReadIntPtr(tokenStruct, 0);
- if (!UnsafeNativeMethods.ConvertSidToStringSidW(SID, out sidStringBuffer)) {
- IntegratedSecurityError(Win32_ConvertSidToStringSidW);
- }
- if (IntPtr.Zero == sidStringBuffer) {
- throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull);
- }
- string sidString = Marshal.PtrToStringUni(sidStringBuffer);
- var lastIdentity = _lastIdentity;
- if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) {
- current = lastIdentity;
- }
- else {
- current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork);
- }
- }
- finally {
- // Marshal.FreeHGlobal does not have a ReliabilityContract
- if (IntPtr.Zero != tokenStruct) {
- SafeNativeMethods.LocalFree(tokenStruct);
- tokenStruct = IntPtr.Zero;
- }
- if (IntPtr.Zero != sidStringBuffer) {
- SafeNativeMethods.LocalFree(sidStringBuffer);
- sidStringBuffer = IntPtr.Zero;
- }
- }
- _lastIdentity = current;
- return current;
- }
- override public int GetHashCode() {
- return _hashCode;
- }
- static private void IntegratedSecurityError(int caller) {
- // passing 1,2,3,4,5 instead of true/false so that with a debugger
- // we could determine more easily which Win32 method call failed
- int lastError = Marshal.GetHRForLastWin32Error();
- if ((Win32_CheckTokenMembership != caller) || (E_NotImpersonationToken != lastError)) {
- Marshal.ThrowExceptionForHR(lastError); // will only throw if (hresult < 0)
- }
- }
-
- }
- }
|