File: DbConnectionPoolIdentity.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (213 lines) | stat: -rw-r--r-- 9,853 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//------------------------------------------------------------------------------
// <copyright file="DbConnectionPoolIdentity.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</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) {
#if !FULL_AOT_RUNTIME
            // 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)
            }
#endif
        }
        
    }
}