2aedb26bc2da6f9b1009e10f48c907b654c247e0
[mono.git] / mcs / class / referencesource / mscorlib / system / security / principal / win32.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 using Microsoft.Win32;
10 using Microsoft.Win32.SafeHandles;
11 using System;
12 using System.Runtime.CompilerServices;
13 using System.Runtime.InteropServices;
14 using System.Security.Permissions;
15 using System.Text;
16 using System.Runtime.Versioning;
17
18 namespace System.Security.Principal
19 {
20     using BOOL = System.Int32;
21     using DWORD = System.UInt32;
22     using System.Globalization;
23     using System.Diagnostics.Contracts;
24
25     [Flags]
26     internal enum PolicyRights
27     {
28         POLICY_VIEW_LOCAL_INFORMATION            = 0x00000001,
29         POLICY_VIEW_AUDIT_INFORMATION            = 0x00000002,
30         POLICY_GET_PRIVATE_INFORMATION           = 0x00000004,
31         POLICY_TRUST_ADMIN                       = 0x00000008,
32         POLICY_CREATE_ACCOUNT                    = 0x00000010,
33         POLICY_CREATE_SECRET                     = 0x00000020,
34         POLICY_CREATE_PRIVILEGE                  = 0x00000040,
35         POLICY_SET_DEFAULT_QUOTA_LIMITS          = 0x00000080,
36         POLICY_SET_AUDIT_REQUIREMENTS            = 0x00000100,
37         POLICY_AUDIT_LOG_ADMIN                   = 0x00000200,
38         POLICY_SERVER_ADMIN                      = 0x00000400,
39         POLICY_LOOKUP_NAMES                      = 0x00000800,
40         POLICY_NOTIFICATION                      = 0x00001000,
41     }
42
43     internal static class Win32
44     {
45         internal const BOOL FALSE = 0;
46         internal const BOOL TRUE = 1;
47
48         private static bool _LsaLookupNames2Supported;
49         private static bool _WellKnownSidApisSupported;
50
51         [System.Security.SecuritySafeCritical]  // auto-generated
52         static Win32() 
53         {
54             
55             Win32Native.OSVERSIONINFO osvi = new Win32Native.OSVERSIONINFO();
56
57             bool r = Environment.GetVersion(osvi);
58             if ( !r )
59             {
60                 Contract.Assert( r, "OSVersion native call failed." );
61                 throw new SystemException( Environment.GetResourceString( "InvalidOperation_GetVersion" ));
62             }
63                 if (osvi.MajorVersion > 5 || osvi.MinorVersion > 0 ) // Windows XP/2003 and above
64                 {
65
66                     //
67                     // LsaLookupNames2 supported only on XP and Windows 2003 and above
68                     //
69                     _LsaLookupNames2Supported = true;
70                     _WellKnownSidApisSupported = true;
71                 }
72                 else 
73                 {
74                     // Win2000
75                     _LsaLookupNames2Supported = false;
76                 
77
78                     //
79                     // WellKnownSid apis are only supported on Windows 2000 SP3 and above
80                     // (so we need sp info)
81                     //
82                     Win32Native.OSVERSIONINFOEX osviex = new Win32Native.OSVERSIONINFOEX();
83
84                     r = Environment.GetVersionEx(osviex);
85                     if ( !r )
86                     {
87                         Contract.Assert( r, "OSVersion native call failed");
88                         throw new SystemException( Environment.GetResourceString( "InvalidOperation_GetVersion" ));
89                     }
90
91                     if (osviex.ServicePackMajor < 3) 
92                     {
93                         _WellKnownSidApisSupported = false;    
94                     }
95                     else 
96                     {
97                         _WellKnownSidApisSupported = true; 
98                     }
99                 }
100             }
101
102         internal static bool LsaLookupNames2Supported
103         {
104             get {
105                 return _LsaLookupNames2Supported;
106             }
107         }
108
109         internal static bool WellKnownSidApisSupported
110         {
111             get {
112                 return _WellKnownSidApisSupported;
113             }
114         }
115
116         //
117         // Wrapper around advapi32.LsaOpenPolicy
118         //
119
120         [System.Security.SecurityCritical]  // auto-generated
121         internal static SafeLsaPolicyHandle LsaOpenPolicy(
122             string systemName,
123             PolicyRights rights )
124         {
125             uint ReturnCode;
126             SafeLsaPolicyHandle Result;
127             Win32Native.LSA_OBJECT_ATTRIBUTES Loa;
128
129             Loa.Length = Marshal.SizeOf( typeof( Win32Native.LSA_OBJECT_ATTRIBUTES ));
130             Loa.RootDirectory = IntPtr.Zero;
131             Loa.ObjectName = IntPtr.Zero;
132             Loa.Attributes = 0;
133             Loa.SecurityDescriptor = IntPtr.Zero;
134             Loa.SecurityQualityOfService = IntPtr.Zero;
135
136             if ( 0 == ( ReturnCode = Win32Native.LsaOpenPolicy( systemName, ref Loa, ( int )rights, out Result )))
137             {
138                 return Result;
139             }
140             else if ( ReturnCode == Win32Native.STATUS_ACCESS_DENIED ) 
141             {
142                 throw new UnauthorizedAccessException();
143             }
144             else if ( ReturnCode == Win32Native.STATUS_INSUFFICIENT_RESOURCES ||
145                       ReturnCode == Win32Native.STATUS_NO_MEMORY ) 
146             {
147                 throw new OutOfMemoryException();
148             }
149             else
150             {
151                 int win32ErrorCode = Win32Native.LsaNtStatusToWinError(unchecked((int) ReturnCode));
152                 
153                 throw new SystemException(Win32Native.GetMessage(win32ErrorCode));
154             }
155         }
156
157         [System.Security.SecurityCritical]  // auto-generated
158         internal static byte[] ConvertIntPtrSidToByteArraySid( IntPtr binaryForm )
159         {
160             byte[] ResultSid;
161
162             //
163             // Verify the revision (just sanity, should never fail to be 1)
164             //
165
166             byte Revision = Marshal.ReadByte( binaryForm, 0 );
167
168             if ( Revision != SecurityIdentifier.Revision )
169             {
170                 throw new ArgumentException(Environment.GetResourceString( "IdentityReference_InvalidSidRevision" ), "binaryForm");
171             }
172
173             //
174             // Need the subauthority count in order to figure out how many bytes to read
175             //
176
177             byte SubAuthorityCount = Marshal.ReadByte( binaryForm, 1 );
178
179             if ( SubAuthorityCount < 0 ||
180                 SubAuthorityCount > SecurityIdentifier.MaxSubAuthorities )
181             {
182                 throw new ArgumentException(Environment.GetResourceString( "IdentityReference_InvalidNumberOfSubauthorities", SecurityIdentifier.MaxSubAuthorities), "binaryForm");
183             }
184
185             //
186             // Compute the size of the binary form of this SID and allocate the memory
187             //
188
189             int BinaryLength = 1 + 1 + 6 + SubAuthorityCount * 4;
190             ResultSid = new byte[ BinaryLength ];
191
192             //
193             // Extract the data from the returned pointer
194             //
195
196             Marshal.Copy( binaryForm, ResultSid, 0, BinaryLength );
197
198             return ResultSid;
199         }
200
201         //
202         // Wrapper around advapi32.ConvertStringSidToSidW
203         //
204
205         [System.Security.SecurityCritical]  // auto-generated
206         internal static int CreateSidFromString(
207             string stringSid,
208             out byte[] resultSid
209             )
210         {
211             int ErrorCode;
212             IntPtr ByteArray = IntPtr.Zero;
213
214             try
215             {
216                 if ( TRUE != Win32Native.ConvertStringSidToSid( stringSid, out ByteArray ))
217                 {
218                     ErrorCode = Marshal.GetLastWin32Error();
219                     goto Error;
220                 }
221
222                 resultSid = ConvertIntPtrSidToByteArraySid( ByteArray );
223             }
224             finally
225             {
226                 //
227                 // Now is a good time to get rid of the returned pointer
228                 //
229
230                 Win32Native.LocalFree( ByteArray );
231             }
232
233             //
234             // Now invoke the SecurityIdentifier factory method to create the result
235             //
236
237             return Win32Native.ERROR_SUCCESS;
238
239         Error:
240
241             resultSid = null;
242             return ErrorCode;
243         }
244
245         //
246         // Wrapper around advapi32.CreateWellKnownSid
247         //
248
249         [System.Security.SecurityCritical]  // auto-generated
250         internal static int CreateWellKnownSid(
251             WellKnownSidType sidType,
252             SecurityIdentifier domainSid,
253             out byte[] resultSid
254             )
255         {
256
257             //
258             // Check if the api is supported
259             //
260             if (!WellKnownSidApisSupported) {
261                 throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
262             }
263         
264             //
265             // Passing an array as big as it can ever be is a small price to pay for
266             // not having to P/Invoke twice (once to get the buffer, once to get the data)
267             //
268
269             uint length = ( uint )SecurityIdentifier.MaxBinaryLength;
270             resultSid = new byte[ length ];
271
272             if ( FALSE != Win32Native.CreateWellKnownSid(( int )sidType, domainSid == null ? null : domainSid.BinaryForm, resultSid, ref length ))
273             {
274                 return Win32Native.ERROR_SUCCESS;
275             }
276             else
277             {
278                 resultSid = null;
279
280                 return Marshal.GetLastWin32Error();
281             }
282         }
283
284         //
285         // Wrapper around advapi32.EqualDomainSid
286         //
287
288         [System.Security.SecurityCritical]  // auto-generated
289         internal static bool IsEqualDomainSid( SecurityIdentifier sid1, SecurityIdentifier sid2 )
290         {
291             //
292             // Check if the api is supported
293             //
294             if (!WellKnownSidApisSupported) {
295                 throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
296             }
297         
298             if ( sid1 == null || sid2 == null )
299             {
300                 return false;
301             }
302             else
303             {
304                 bool result;
305                 
306                 byte[] BinaryForm1 = new Byte[sid1.BinaryLength];
307                 sid1.GetBinaryForm( BinaryForm1, 0 );
308
309                 byte[] BinaryForm2 = new Byte[sid2.BinaryLength];
310                 sid2.GetBinaryForm( BinaryForm2, 0 );
311
312                 return ( Win32Native.IsEqualDomainSid( BinaryForm1, BinaryForm2, out result ) == FALSE ? false : result );
313             }
314         }
315
316         /// <summary>
317         ///     Setup the size of the buffer Windows provides for an LSA_REFERENCED_DOMAIN_LIST
318         /// </summary>
319         [System.Security.SecurityCritical]  // auto-generated
320         internal static void InitializeReferencedDomainsPointer(SafeLsaMemoryHandle referencedDomains)
321         {
322             Contract.Assert(referencedDomains != null, "referencedDomains != null");
323
324             // We don't know the real size of the referenced domains yet, so we need to set an initial
325             // size based on the LSA_REFERENCED_DOMAIN_LIST structure, then resize it to include all of
326             // the domains.
327             referencedDomains.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.LSA_REFERENCED_DOMAIN_LIST)));
328             Win32Native.LSA_REFERENCED_DOMAIN_LIST domainList = referencedDomains.Read<Win32Native.LSA_REFERENCED_DOMAIN_LIST>(0);
329
330             unsafe
331             {
332                 byte* pRdl = null;
333                 RuntimeHelpers.PrepareConstrainedRegions();
334                 try
335                 {
336                     referencedDomains.AcquirePointer(ref pRdl);
337
338                     // If there is a trust information list, then the buffer size is the end of that list minus
339                     // the beginning of the domain list. Otherwise, then the buffer is just the size of the
340                     // referenced domain list structure, which is what we defaulted to.
341                     if (!domainList.Domains.IsNull())
342                     {
343                         Win32Native.LSA_TRUST_INFORMATION* pTrustInformation = (Win32Native.LSA_TRUST_INFORMATION*)domainList.Domains;
344                         pTrustInformation = pTrustInformation + domainList.Entries;
345
346                         long bufferSize = (byte*)pTrustInformation - pRdl;
347                         Contract.Assert(bufferSize > 0, "bufferSize > 0");
348                         referencedDomains.Initialize((ulong)bufferSize);
349                     }
350                 }
351                 finally
352                 {
353                     if (pRdl != null)
354                         referencedDomains.ReleasePointer();
355                 }
356             }
357         }
358
359         //
360         // Wrapper around avdapi32.GetWindowsAccountDomainSid
361         //
362
363         [System.Security.SecurityCritical]  // auto-generated
364         internal static int GetWindowsAccountDomainSid(
365             SecurityIdentifier sid,
366             out SecurityIdentifier resultSid
367             )
368         {
369
370             //
371             // Check if the api is supported
372             //
373             if (!WellKnownSidApisSupported) {
374                 throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
375             }
376         
377             //
378             // Passing an array as big as it can ever be is a small price to pay for
379             // not having to P/Invoke twice (once to get the buffer, once to get the data)
380             //
381
382             byte[] BinaryForm = new Byte[sid.BinaryLength];
383             sid.GetBinaryForm( BinaryForm, 0 );
384             uint sidLength = ( uint )SecurityIdentifier.MaxBinaryLength;
385             byte[] resultSidBinary = new byte[ sidLength ];
386
387             if ( FALSE != Win32Native.GetWindowsAccountDomainSid( BinaryForm, resultSidBinary, ref sidLength ))
388             {
389                 resultSid = new SecurityIdentifier( resultSidBinary, 0 );
390
391                 return Win32Native.ERROR_SUCCESS;
392             }
393             else
394             {
395                 resultSid = null;
396
397                 return Marshal.GetLastWin32Error();
398             }
399         }
400
401         //
402         // Wrapper around advapi32.IsWellKnownSid
403         //
404
405         [System.Security.SecurityCritical]  // auto-generated
406         internal static bool IsWellKnownSid(
407             SecurityIdentifier sid,
408             WellKnownSidType type
409             )
410         {
411             //
412             // Check if the api is supported
413             //
414             if (!WellKnownSidApisSupported) {
415                 throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresW2kSP3" ));
416             }
417       
418             byte[] BinaryForm = new byte[sid.BinaryLength];
419             sid.GetBinaryForm( BinaryForm, 0 );
420
421             if ( FALSE == Win32Native.IsWellKnownSid( BinaryForm, ( int )type ))
422             {
423                 return false;
424             }
425             else
426             {
427                 return true;
428             }
429         }
430
431
432         // When the CLR is hosted, the host gets to implement these calls,
433         // otherwise, we call down into the Win32 APIs.
434
435 #if FEATURE_IMPERSONATION
436         [System.Security.SecurityCritical]  // auto-generated
437         [ResourceExposure(ResourceScope.Process)]
438         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
439         internal static extern int ImpersonateLoggedOnUser (SafeAccessTokenHandle hToken);
440
441         [System.Security.SecurityCritical]  // auto-generated
442         [ResourceExposure(ResourceScope.Process)]
443         [MethodImplAttribute(MethodImplOptions.InternalCall)]
444         internal static extern int OpenThreadToken (TokenAccessLevels dwDesiredAccess, WinSecurityContext OpenAs, out SafeAccessTokenHandle phThreadToken);
445
446         [System.Security.SecurityCritical]  // auto-generated
447         [ResourceExposure(ResourceScope.None)]
448         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
449         internal static extern int RevertToSelf ();
450
451         [System.Security.SecurityCritical]  // auto-generated
452         [ResourceExposure(ResourceScope.None)]
453         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
454         internal static extern int SetThreadToken(SafeAccessTokenHandle hToken);
455 #endif        
456     }
457 }