Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / principal / windowsidentity.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 //
10 // WindowsIdentity.cs
11 //
12 // Representation of a process/thread token.
13 //
14
15 namespace System.Security.Principal
16 {
17     using System.Diagnostics.Contracts;    
18     using System.Reflection;
19     using System.Runtime.CompilerServices;
20     #if FEATURE_CORRUPTING_EXCEPTIONS
21     using System.Runtime.ExceptionServices;
22     #endif // FEATURE_CORRUPTING_EXCEPTIONS
23     using System.Runtime.InteropServices;
24     using System.Runtime.Serialization;
25     using System.Runtime.Versioning;
26     using System.Security.AccessControl;
27     using System.Security.Permissions;
28     using System.Text;
29     using System.Threading;
30     using Microsoft.Win32;
31     using Microsoft.Win32.SafeHandles;
32
33 #if !FEATURE_CORECLR
34     using System.Security.Claims;
35     using System.Collections.ObjectModel;
36     using System.Collections.Generic;
37     using System.Globalization;
38 #endif
39
40     [Serializable]
41     [System.Runtime.InteropServices.ComVisible(true)]
42     public enum WindowsAccountType {
43         Normal      = 0,
44         Guest       = 1,
45         System      = 2,
46         Anonymous   = 3
47     }
48
49     // Keep in sync with vm\comprincipal.h
50     internal enum WinSecurityContext {
51         Thread = 1, // OpenAsSelf = false
52         Process = 2, // OpenAsSelf = true
53         Both = 3 // OpenAsSelf = true, then OpenAsSelf = false
54     }
55
56     internal enum ImpersonationQueryResult {
57         Impersonated    = 0,    // current thread is impersonated
58         NotImpersonated = 1,    // current thread is not impersonated
59         Failed          = 2     // failed to query 
60     }
61
62     [Serializable]
63     [System.Runtime.InteropServices.ComVisible(true)]
64 #if !FEATURE_CORECLR
65     public class WindowsIdentity : ClaimsIdentity, ISerializable, IDeserializationCallback, IDisposable {
66 #else
67     public class WindowsIdentity : IIdentity, ISerializable, IDeserializationCallback, IDisposable {
68 #endif
69         [System.Security.SecurityCritical] // auto-generated
70         static SafeAccessTokenHandle s_invalidTokenHandle = SafeAccessTokenHandle.InvalidHandle; 
71         private string m_name = null;
72         private SecurityIdentifier m_owner = null;
73         private SecurityIdentifier m_user = null;
74         private object m_groups = null;
75         [System.Security.SecurityCritical] // auto-generated
76         private SafeAccessTokenHandle m_safeTokenHandle = SafeAccessTokenHandle.InvalidHandle;
77         private string m_authType = null;
78         private int m_isAuthenticated = -1;
79         private volatile TokenImpersonationLevel m_impersonationLevel;
80         private volatile bool m_impersonationLevelInitialized;
81         private static RuntimeConstructorInfo s_specialSerializationCtor;
82
83 #if !FEATURE_CORECLR
84
85         [NonSerialized]
86         public new const string DefaultIssuer = @"AD AUTHORITY";
87         
88         [NonSerialized]
89         string m_issuerName = DefaultIssuer;
90         
91         [NonSerialized]
92         private object m_claimsIntiailizedLock = new object();
93         
94         [NonSerialized]
95         volatile bool m_claimsInitialized;
96
97         [NonSerialized]
98         List<Claim> m_deviceClaims;
99
100         [NonSerialized]
101         List<Claim> m_userClaims;
102
103 #endif
104
105         //
106         // Constructors.
107         //
108         
109         [System.Security.SecuritySafeCritical]  // auto-generated
110         static WindowsIdentity()
111         {
112             s_specialSerializationCtor = typeof(WindowsIdentity).GetConstructor(
113                 BindingFlags.Instance | BindingFlags.NonPublic,
114                 null,
115                 new Type[] { typeof(SerializationInfo) },
116                 null) as RuntimeConstructorInfo;
117         }
118
119         [System.Security.SecurityCritical]  // auto-generated
120 #if !FEATURE_CORECLR
121         private WindowsIdentity ()
122             : base( null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid ) {}
123 #else
124         private WindowsIdentity () {}
125 #endif
126
127         [System.Security.SecurityCritical]  // auto-generated
128         internal WindowsIdentity (SafeAccessTokenHandle safeTokenHandle) : this (safeTokenHandle.DangerousGetHandle(), null, -1) {
129             GC.KeepAlive(safeTokenHandle);
130         }
131
132         [System.Security.SecuritySafeCritical]  // auto-generated
133         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
134         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
135         public WindowsIdentity (IntPtr userToken) : this (userToken, null, -1) {}
136
137         [System.Security.SecuritySafeCritical]  // auto-generated
138         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
139         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
140         public WindowsIdentity (IntPtr userToken, string type) : this (userToken, type, -1) {}
141
142         [System.Security.SecuritySafeCritical]  // auto-generated
143         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
144         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
145         public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType) : this (userToken, type, -1) {}
146
147         [System.Security.SecuritySafeCritical]  // auto-generated
148         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
149         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
150         public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) 
151             : this (userToken, type, isAuthenticated ? 1 : 0) {}
152
153         [System.Security.SecurityCritical]  // auto-generated
154
155
156         private WindowsIdentity (IntPtr userToken, string authType, int isAuthenticated )
157 #if !FEATURE_CORECLR
158             : base(null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid) 
159 #endif
160         {
161             CreateFromToken(userToken);
162             m_authType = authType;
163             m_isAuthenticated = isAuthenticated;
164         }
165
166         [System.Security.SecurityCritical]  // auto-generated
167         [ResourceExposure(ResourceScope.None)]
168         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
169         private void CreateFromToken (IntPtr userToken) {
170             if (userToken == IntPtr.Zero)
171                 throw new ArgumentException(Environment.GetResourceString("Argument_TokenZero"));
172             Contract.EndContractBlock();
173
174             // Find out if the specified token is a valid.
175             uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
176             bool result = Win32Native.GetTokenInformation(userToken, (uint) TokenInformationClass.TokenType,
177                                                           SafeLocalAllocHandle.InvalidHandle, 0, out dwLength);
178             if (Marshal.GetLastWin32Error() == Win32Native.ERROR_INVALID_HANDLE)
179                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
180
181             if (!Win32Native.DuplicateHandle(Win32Native.GetCurrentProcess(),
182                                              userToken,
183                                              Win32Native.GetCurrentProcess(),
184                                              ref m_safeTokenHandle,
185                                              0,
186                                              true,
187                                              Win32Native.DUPLICATE_SAME_ACCESS))
188                 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
189         }
190
191         [System.Security.SecuritySafeCritical]  // auto-generated
192         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
193         public WindowsIdentity (string sUserPrincipalName) : this (sUserPrincipalName, null) {}
194
195         [System.Security.SecuritySafeCritical]  // auto-generated
196         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
197
198
199         public WindowsIdentity (string sUserPrincipalName, string type )
200 #if !FEATURE_CORECLR
201             : base( null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid )
202 #endif
203         {
204             KerbS4ULogon(sUserPrincipalName, ref m_safeTokenHandle);
205         }
206
207         //
208         // We cannot make sure the token will stay alive
209         // until it is being deserialized in another AppDomain. We do not have a way to capture 
210         // the state of a token (just a pointer to kernel memory) and re-construct it later
211         // and even if we did (via calling NtQueryInformationToken and relying on the token undocumented
212         // format), constructing a token requires TCB privilege. We need to address the "serializable" 
213         // nature of WindowsIdentity since it is not obvious that can be achieved at all.
214         //
215
216         [System.Security.SecuritySafeCritical]  // auto-generated
217         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
218         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.SerializationFormatter )]
219         public WindowsIdentity (SerializationInfo info, StreamingContext context) : this(info)
220         {
221         }
222
223         // This is a copy of the serialization constructor above but without the
224         // security demand that's slow and breaks partial trust scenarios
225         // without an expensive assert in place in the remoting code. Instead we
226         // special case this class and call the private constructor directly
227         // (changing the demand above is considered a breaking change, even
228         // though nobody else should have been using a serialization constructor
229         // directly).
230         [System.Security.SecurityCritical]  // auto-generated
231         private WindowsIdentity(SerializationInfo info)
232 #if !FEATURE_CORECLR
233             : base(info)
234 #endif
235         {
236
237             #if !FEATURE_CORECLR
238             m_claimsInitialized = false;
239             #endif
240
241             IntPtr userToken = (IntPtr) info.GetValue("m_userToken", typeof(IntPtr));
242             if (userToken != IntPtr.Zero)
243                 CreateFromToken(userToken);
244         }
245
246         /// <internalonly/>
247         [System.Security.SecurityCritical]  // auto-generated_required
248         void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {
249 #if !FEATURE_CORECLR
250                 base.GetObjectData(info, context);
251 #endif
252             info.AddValue("m_userToken", m_safeTokenHandle.DangerousGetHandle());
253         }
254
255         /// <internalonly/>
256         void IDeserializationCallback.OnDeserialization (Object sender) {}
257
258         //
259         // Factory methods.
260         //
261
262         
263         [System.Security.SecuritySafeCritical]  // auto-generated
264         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
265         public static WindowsIdentity GetCurrent () {
266            return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
267         }
268
269         [System.Security.SecuritySafeCritical]  // auto-generated
270         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
271         public static WindowsIdentity GetCurrent (bool ifImpersonating) {
272            return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, ifImpersonating);
273         }
274
275         [System.Security.SecuritySafeCritical]  // auto-generated
276         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
277         public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess) {
278            return GetCurrentInternal(desiredAccess, false);
279         }
280
281         // GetAnonymous() is used heavily in ASP.NET requests as a dummy identity to indicate
282         // the request is anonymous. It does not represent a real process or thread token so
283         // it cannot impersonate or do anything useful. Note this identity does not represent the
284         // usual concept of an anonymous token, and the name is simply misleading but we cannot change it now.
285
286         [System.Security.SecuritySafeCritical]  // auto-generated
287         public static WindowsIdentity GetAnonymous () {
288             return new WindowsIdentity();
289         }
290
291         //
292         // Properties.
293         //
294         // this is defined 'override sealed' for back compat. Il generated is 'virtual final' and this needs to be the same.
295 #if !FEATURE_CORECLR
296         public override sealed string AuthenticationType {
297 #else
298         public string AuthenticationType {
299 #endif
300             [System.Security.SecuritySafeCritical]  // auto-generated
301             get {
302                 // If this is an anonymous identity, return an empty string
303                 if (m_safeTokenHandle.IsInvalid)
304                     return String.Empty;
305
306                 if (m_authType == null) {
307                     Win32Native.LUID authId = GetLogonAuthId(m_safeTokenHandle);
308                     if (authId.LowPart == Win32Native.ANONYMOUS_LOGON_LUID)
309                         return String.Empty; // no authentication, just return an empty string
310
311                     SafeLsaReturnBufferHandle pLogonSessionData = SafeLsaReturnBufferHandle.InvalidHandle;
312                     try {
313                         int status = Win32Native.LsaGetLogonSessionData(ref authId, ref pLogonSessionData);
314                     if (status < 0) // non-negative numbers indicate success
315                         throw GetExceptionFromNtStatus(status);
316
317                         pLogonSessionData.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.SECURITY_LOGON_SESSION_DATA)));
318
319                         Win32Native.SECURITY_LOGON_SESSION_DATA logonSessionData = pLogonSessionData.Read<Win32Native.SECURITY_LOGON_SESSION_DATA>(0);
320                         return Marshal.PtrToStringUni(logonSessionData.AuthenticationPackage.Buffer);
321                     }
322                     finally {
323                         if (!pLogonSessionData.IsInvalid)
324                             pLogonSessionData.Dispose();
325                     }
326                 }
327
328                 return m_authType;
329             }
330         }
331
332
333         [ComVisible(false)]
334         public TokenImpersonationLevel ImpersonationLevel {
335             [System.Security.SecuritySafeCritical]  // auto-generated
336             get {
337                 // If two threads ---- here, they'll both set m_impersonationLevel to the same value,
338                 // which is ok.
339                 if (!m_impersonationLevelInitialized) {
340                     TokenImpersonationLevel impersonationLevel = TokenImpersonationLevel.None;
341                     // If this is an anonymous identity
342                     if (m_safeTokenHandle.IsInvalid) {
343                         impersonationLevel = TokenImpersonationLevel.Anonymous;
344                     }
345                     else {
346                         TokenType tokenType = (TokenType)GetTokenInformation<int>(TokenInformationClass.TokenType);
347                         if (tokenType == TokenType.TokenPrimary) {
348                             impersonationLevel = TokenImpersonationLevel.None; // primary token;
349                         }
350                         else {
351                             /// This is an impersonation token, get the impersonation level
352                             int level = GetTokenInformation<int>(TokenInformationClass.TokenImpersonationLevel);
353                             impersonationLevel = (TokenImpersonationLevel)level + 1;
354                         }
355                     }
356
357                     m_impersonationLevel = impersonationLevel;
358                     m_impersonationLevelInitialized = true;
359                 }
360
361                 return m_impersonationLevel;
362             }
363         }
364
365 #if !FEATURE_CORECLR
366         public override bool IsAuthenticated {
367 #else
368         public virtual bool IsAuthenticated {
369 #endif
370
371             get {
372                 if (m_isAuthenticated == -1) {
373                     // There is a known bug where this approach will not work correctly for domain guests (will return false
374                     // instead of true). But this is a corner-case that is not very interesting.
375 #if !FEATURE_CORECLR
376                     m_isAuthenticated = CheckNtTokenForSid(new SecurityIdentifier(IdentifierAuthority.NTAuthority,
377                                                                     new int[] { Win32Native.SECURITY_AUTHENTICATED_USER_RID })) ? 1 : 0;
378 #else                    
379                     WindowsPrincipal wp = new WindowsPrincipal(this);
380                     SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
381                                                                     new int[] {Win32Native.SECURITY_AUTHENTICATED_USER_RID});
382                     m_isAuthenticated = wp.IsInRole(sid) ? 1 : 0;
383 #endif
384
385                 }
386
387                 return m_isAuthenticated == 1;
388             }
389         }
390
391 #if !FEATURE_CORECLR
392         [System.Security.SecuritySafeCritical]
393         [ComVisible(false)]
394         bool CheckNtTokenForSid (SecurityIdentifier sid) {
395
396             Contract.EndContractBlock();
397
398             // special case the anonymous identity.
399             if (m_safeTokenHandle.IsInvalid)
400                 return false;
401
402             // CheckTokenMembership expects an impersonation token
403             SafeAccessTokenHandle token = SafeAccessTokenHandle.InvalidHandle;
404             TokenImpersonationLevel til = ImpersonationLevel;
405             bool isMember = false;
406
407             try {
408                 if (til == TokenImpersonationLevel.None) {
409                     if (!Win32Native.DuplicateTokenEx(m_safeTokenHandle,
410                                                       (uint) TokenAccessLevels.Query,
411                                                       IntPtr.Zero,
412                                                       (uint) TokenImpersonationLevel.Identification,
413                                                       (uint) TokenType.TokenImpersonation,
414                                                       ref token))
415                         throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
416                 }
417
418                 
419                 // CheckTokenMembership will check if the SID is both present and enabled in the access token.
420                 if (!Win32Native.CheckTokenMembership((til != TokenImpersonationLevel.None ? m_safeTokenHandle : token),
421                                                       sid.BinaryForm,
422                                                       ref isMember))
423                     throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
424             }
425             finally {
426                 if (token != SafeAccessTokenHandle.InvalidHandle) {
427                     token.Dispose();
428                 }
429             }
430
431             return isMember;
432         }
433 #endif
434
435         //
436         // IsGuest, IsSystem and IsAnonymous are maintained for compatibility reasons. It is always
437         // possible to extract this same information from the User SID property and the new
438         // (and more general) methods defined in the SID class (IsWellKnown, etc...).
439         //
440
441         public virtual bool IsGuest {
442             [System.Security.SecuritySafeCritical]  // auto-generated
443             get {
444                 // special case the anonymous identity.
445                 if (m_safeTokenHandle.IsInvalid)
446                     return false;
447
448 #if !FEATURE_CORECLR
449                 return CheckNtTokenForSid(new SecurityIdentifier(IdentifierAuthority.NTAuthority,
450                                                 new int[] { Win32Native.SECURITY_BUILTIN_DOMAIN_RID, (int)WindowsBuiltInRole.Guest }));
451 #else
452                 WindowsPrincipal principal = new WindowsPrincipal(this);
453                 return principal.IsInRole(WindowsBuiltInRole.Guest);
454 #endif
455
456             }
457         }
458
459         public virtual bool IsSystem {
460             [System.Security.SecuritySafeCritical]  // auto-generated
461             get {
462                 // special case the anonymous identity.
463                 if (m_safeTokenHandle.IsInvalid)
464                     return false;
465                 SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority, 
466                                                                 new int[] {Win32Native.SECURITY_LOCAL_SYSTEM_RID});
467                 return (this.User == sid);
468             }
469         }
470
471         public virtual bool IsAnonymous {
472             [System.Security.SecuritySafeCritical]  // auto-generated
473             get {
474                 // special case the anonymous identity.
475                 if (m_safeTokenHandle.IsInvalid)
476                     return true;
477                 SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority, 
478                                                                 new int[] {Win32Native.SECURITY_ANONYMOUS_LOGON_RID});
479                 return (this.User == sid);
480             }
481         }
482
483 #if !FEATURE_CORECLR
484         public override string Name {
485 #else
486         public virtual string Name {
487 #endif
488             [System.Security.SecuritySafeCritical]  // auto-generated
489             get {
490                 return GetName();
491             }
492         }
493
494         [System.Security.SecurityCritical]  // auto-generated
495         [DynamicSecurityMethodAttribute()]
496         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
497         internal String GetName()
498         {
499             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
500             // special case the anonymous identity.
501             if (m_safeTokenHandle.IsInvalid)
502                 return String.Empty;
503             
504             if (m_name == null) 
505             {
506                 // revert thread impersonation for the duration of the call to get the name.
507                 using (SafeRevertToSelf(ref stackMark))  
508                 {
509                     NTAccount ntAccount = this.User.Translate(typeof(NTAccount)) as NTAccount;
510                     m_name = ntAccount.ToString();
511                 }
512             }
513             
514             return m_name;
515         }
516
517         [ComVisible(false)]
518         public SecurityIdentifier Owner {
519             [System.Security.SecuritySafeCritical]  // auto-generated
520             get {
521                 // special case the anonymous identity.
522                 if (m_safeTokenHandle.IsInvalid)
523                     return null;
524
525                 if (m_owner == null) {
526                     using (SafeLocalAllocHandle tokenOwner = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenOwner)) {
527                         m_owner = new SecurityIdentifier(tokenOwner.Read<IntPtr>(0), true);
528                     }
529                 }
530
531                 return m_owner;
532             }
533         }
534
535         [ComVisible(false)]
536         public SecurityIdentifier User {
537             [System.Security.SecuritySafeCritical]  // auto-generated
538             get {
539                 // special case the anonymous identity.
540                 if (m_safeTokenHandle.IsInvalid)
541                     return null;
542
543                 if (m_user == null) {
544                     using (SafeLocalAllocHandle tokenUser = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser)) {
545                         m_user = new SecurityIdentifier(tokenUser.Read<IntPtr>(0), true);
546                     }
547                 }
548
549                 return m_user;
550             }
551         }
552
553         public IdentityReferenceCollection Groups {
554             [System.Security.SecuritySafeCritical]  // auto-generated
555             get {
556                 // special case the anonymous identity.
557                 if (m_safeTokenHandle.IsInvalid)
558                     return null;
559
560                 if (m_groups == null) {
561                     IdentityReferenceCollection groups = new IdentityReferenceCollection();
562                     using (SafeLocalAllocHandle pGroups = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups)) {
563
564                         uint groupCount = pGroups.Read<uint>(0); 
565                         // Work-around bug on WS03 that only populates the GroupCount field of TOKEN_GROUPS if the count is 0
566                         // In that situation, attempting to read the entire TOKEN_GROUPS structure will lead to InsufficientBuffer exception 
567                         // since the field is only 4 bytes long (uint only, for GroupCount), but we try to read more (including the pointer to GroupDetails).
568                         if (groupCount != 0)
569                         {
570
571                             Win32Native.TOKEN_GROUPS tokenGroups = pGroups.Read<Win32Native.TOKEN_GROUPS>(0);
572                             Win32Native.SID_AND_ATTRIBUTES[] groupDetails = new Win32Native.SID_AND_ATTRIBUTES[tokenGroups.GroupCount];
573
574                             pGroups.ReadArray((uint)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups").ToInt32(),
575                                               groupDetails,
576                                               0,
577                                               groupDetails.Length);
578
579                             foreach (Win32Native.SID_AND_ATTRIBUTES group in groupDetails)
580                             {
581                                 // Ignore disabled, logon ID, and deny-only groups.
582                                 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
583                                 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED) {
584                                     groups.Add(new SecurityIdentifier(group.Sid, true ));
585                                 }
586                             }
587                         }
588                     }
589                     Interlocked.CompareExchange(ref m_groups, groups, null);
590                 }
591
592                 return m_groups as IdentityReferenceCollection;
593             }
594         }
595
596         //
597         // Note this property does not duplicate the token. This is also the same as V1/Everett behaviour.
598         //
599
600         public virtual IntPtr Token {
601             [System.Security.SecuritySafeCritical]  // auto-generated
602             [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
603             get {
604                 return m_safeTokenHandle.DangerousGetHandle();
605             }
606         }
607
608         //
609         // Public methods.
610         //
611         [SecuritySafeCritical]
612         [DynamicSecurityMethodAttribute()]
613         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
614         public static void RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
615         {
616             if (action == null)
617                 throw new ArgumentNullException("action");
618
619             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
620
621             WindowsIdentity wi = null;
622             if (!safeAccessTokenHandle.IsInvalid)
623                 wi = new WindowsIdentity(safeAccessTokenHandle);
624
625             using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
626             {
627                 action();
628             }
629         }
630
631         [SecuritySafeCritical]
632         [DynamicSecurityMethodAttribute()]
633         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
634         public static T RunImpersonated<T>(SafeAccessTokenHandle safeAccessTokenHandle, Func<T> func)
635         {
636             if (func == null)
637                 throw new ArgumentNullException("func");
638
639             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
640
641             WindowsIdentity wi = null;
642             if (!safeAccessTokenHandle.IsInvalid)
643                 wi = new WindowsIdentity(safeAccessTokenHandle);
644
645             T result = default(T);
646             using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
647             {
648                 result = func();
649             }
650
651             return result;
652         }
653
654         [System.Security.SecuritySafeCritical]  // auto-generated
655         [DynamicSecurityMethodAttribute()]
656         [ResourceExposure(ResourceScope.Process)]  // Call from within a CER, or use a RunAsUser helper.
657         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
658         public virtual WindowsImpersonationContext Impersonate () 
659         {
660             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
661             return Impersonate(ref stackMark);
662         }
663
664         [System.Security.SecuritySafeCritical]  // auto-generated
665         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode)]
666         [DynamicSecurityMethodAttribute()]
667         [ResourceExposure(ResourceScope.Process)]  // Call from within a CER, or use a RunAsUser helper.
668         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
669         public static WindowsImpersonationContext Impersonate (IntPtr userToken) 
670         {
671             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
672             if (userToken == IntPtr.Zero)
673                 return SafeRevertToSelf(ref stackMark);
674
675             WindowsIdentity wi = new WindowsIdentity(userToken, null, -1);
676             return wi.Impersonate(ref stackMark);
677         }
678
679         [System.Security.SecurityCritical]  // auto-generated
680         internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
681             if (m_safeTokenHandle.IsInvalid)
682                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));
683
684             return SafeImpersonate(m_safeTokenHandle, this, ref stackMark);
685         }
686
687         [System.Security.SecuritySafeCritical]  // auto-generated
688         [ComVisible(false)]
689         protected virtual void Dispose(bool disposing) {
690             if (disposing) {
691                 if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
692                     m_safeTokenHandle.Dispose();
693             }
694             m_name = null;
695             m_owner = null;
696             m_user = null;
697         }
698
699         [ComVisible(false)]
700         public void Dispose() {
701             Dispose(true);
702         }
703
704         public SafeAccessTokenHandle AccessToken {
705             [System.Security.SecurityCritical]  // auto-generated
706             get {
707                 return m_safeTokenHandle;
708             }
709         }
710
711         //
712         // internal.
713         //
714
715         [System.Security.SecurityCritical]  // auto-generated
716         [ResourceExposure(ResourceScope.None)]
717         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
718         internal static WindowsImpersonationContext SafeRevertToSelf(ref StackCrawlMark stackMark) 
719         {
720             return SafeImpersonate(s_invalidTokenHandle, null, ref stackMark);
721         }
722
723         [System.Security.SecurityCritical]  // auto-generated
724         [ResourceExposure(ResourceScope.Process)]
725         [ResourceConsumption(ResourceScope.Process)]
726         internal static WindowsImpersonationContext SafeImpersonate (SafeAccessTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark) 
727         {
728             bool isImpersonating;
729             int hr = 0;
730             SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr);
731             if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
732                 throw new SecurityException(Win32Native.GetMessage(hr));
733
734             // Set the SafeAccessTokenHandle on the FSD:
735             FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
736             if (secObj == null)
737             {
738                 // Security: REQ_SQ flag is missing. Bad compiler ?
739                 // This can happen when you create delegates over functions that need the REQ_SQ 
740                 throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) );
741             }
742                 
743             WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
744
745             if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
746                 hr = Win32.RevertToSelf();
747                 if (hr < 0)
748                     Environment.FailFast(Win32Native.GetMessage(hr));
749                 // update identity on the thread
750                 UpdateThreadWI(wi);
751                 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
752             } else {
753                 hr = Win32.RevertToSelf();
754                 if (hr < 0)
755                         Environment.FailFast(Win32Native.GetMessage(hr));
756                 hr = Win32.ImpersonateLoggedOnUser(userToken);
757                 if (hr < 0) {
758                     context.Undo();
759                     throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
760                 }
761                 UpdateThreadWI(wi);
762                 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
763             }
764
765             return context;
766         }
767
768         [System.Security.SecurityCritical]  // auto-generated
769         internal static WindowsIdentity GetCurrentThreadWI()
770         {
771             return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextReader());
772         }
773
774         [SecurityCritical]
775         internal static void UpdateThreadWI(WindowsIdentity wi)
776         {
777             // Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
778             Thread currentThread = Thread.CurrentThread;
779             if (currentThread.GetExecutionContextReader().SecurityContext.WindowsIdentity != wi)
780             {
781                 ExecutionContext ec = currentThread.GetMutableExecutionContext(); 
782                 SecurityContext sc = ec.SecurityContext;
783                 if (wi != null && sc == null)
784                 {
785                     // create a new security context on the thread
786                     sc = new SecurityContext();
787                     ec.SecurityContext = sc;
788                 }
789
790                 if (sc != null) // null-check needed here since we will not create an sc if wi is null
791                 {
792                     sc.WindowsIdentity = wi;
793                 }
794             }
795         }
796
797
798         [System.Security.SecurityCritical]  // auto-generated
799         [ResourceExposure(ResourceScope.None)]
800         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
801         internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) {
802             int hr = 0;
803             bool isImpersonating;
804             SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
805             if (safeTokenHandle == null || safeTokenHandle.IsInvalid) {
806                 // either we wanted only ThreadToken - return null
807                 if (threadOnly && !isImpersonating)
808                     return null;
809                 // or there was an error
810                 throw new SecurityException(Win32Native.GetMessage(hr));
811             }
812             WindowsIdentity wi = new WindowsIdentity();
813             wi.m_safeTokenHandle.Dispose();
814             wi.m_safeTokenHandle = safeTokenHandle;
815             return wi;
816         }
817
818         internal static RuntimeConstructorInfo GetSpecialSerializationCtor()
819         {
820             return s_specialSerializationCtor;
821         }
822
823         //
824         // private.
825         //
826
827         private static int GetHRForWin32Error (int dwLastError) {
828             if ((dwLastError & 0x80000000) == 0x80000000)
829                 return dwLastError;
830             else
831                 return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
832         }
833
834         [System.Security.SecurityCritical]  // auto-generated
835         private static Exception GetExceptionFromNtStatus (int status) {
836             if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
837                 return new UnauthorizedAccessException();
838
839             if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
840                 return new OutOfMemoryException();
841
842             int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
843             return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
844         }
845
846         [System.Security.SecurityCritical]  // auto-generated
847         [ResourceExposure(ResourceScope.Process)]
848         [ResourceConsumption(ResourceScope.Process)]
849         private static SafeAccessTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
850             isImpersonating = true;
851             SafeAccessTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
852             if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
853                 // No impersonation
854                 isImpersonating = false;
855                 if (!threadOnly)
856                     safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
857             }
858             return safeTokenHandle;
859         }
860
861         [System.Security.SecurityCritical]  // auto-generated
862         [ResourceExposure(ResourceScope.Process)]
863         [ResourceConsumption(ResourceScope.Process)]
864         private static SafeAccessTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) {
865             hr = 0;
866             SafeAccessTokenHandle safeTokenHandle;
867             if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle))
868                 hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
869             return safeTokenHandle;
870         }
871
872         [System.Security.SecurityCritical]  // auto-generated
873         [ResourceExposure(ResourceScope.Process)]
874         [ResourceConsumption(ResourceScope.Process)]
875         internal static SafeAccessTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
876             SafeAccessTokenHandle safeTokenHandle;
877             hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle);
878             return safeTokenHandle;
879         }
880
881         /// <summary>
882         ///     Get a property from the current token
883         /// </summary>
884         [System.Security.SecurityCritical]  // auto-generated
885         private T GetTokenInformation<T>(TokenInformationClass tokenInformationClass) where T : struct{
886             Contract.Assert(!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed, "!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed");
887
888             using (SafeLocalAllocHandle information = GetTokenInformation(m_safeTokenHandle, tokenInformationClass)) {
889                 Contract.Assert(information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T)),
890                                 "information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T))");
891
892                 return information.Read<T>(0);
893             }
894         }
895
896         //
897         // QueryImpersonation used to test if the current thread is impersonated.
898         // This method doesn't return the thread token (WindowsIdentity).
899         // Although GetCurrentInternal can be used to perform the same test but 
900         // QueryImpersonation is optimized for the perf.
901         // 
902         [System.Security.SecurityCritical]  // auto-generated
903         [ResourceExposure(ResourceScope.Process)]
904         [ResourceConsumption(ResourceScope.Process)]
905         internal static ImpersonationQueryResult QueryImpersonation() {
906             SafeAccessTokenHandle safeTokenHandle = null;
907             int hr = Win32.OpenThreadToken(TokenAccessLevels.Query,  WinSecurityContext.Thread, out safeTokenHandle);
908                         
909             if (safeTokenHandle != null) {
910                 Contract.Assert(hr == 0, "[WindowsIdentity..QueryImpersonation] - hr == 0");
911                 safeTokenHandle.Close();
912                 return ImpersonationQueryResult.Impersonated;
913             } 
914
915             if (hr == GetHRForWin32Error(Win32Native.ERROR_ACCESS_DENIED)) {
916                 // thread is impersonated because the thread was there (and we failed to open it).
917                 return ImpersonationQueryResult.Impersonated;
918             } 
919             
920             if (hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
921                 // definitely not impersonating
922                 return ImpersonationQueryResult.NotImpersonated;
923             }
924             
925             // Unexpected failure.
926             return ImpersonationQueryResult.Failed;
927         }
928
929         [System.Security.SecurityCritical]  // auto-generated
930         private static Win32Native.LUID GetLogonAuthId (SafeAccessTokenHandle safeTokenHandle) {
931             using (SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics)) {
932                 Win32Native.TOKEN_STATISTICS statistics = pStatistics.Read<Win32Native.TOKEN_STATISTICS>(0);
933             return statistics.AuthenticationId;
934         }
935         }
936
937         [System.Security.SecurityCritical]
938         private static SafeLocalAllocHandle GetTokenInformation (SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass) {
939             SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
940             uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
941             bool result = Win32Native.GetTokenInformation(tokenHandle, 
942                                                           (uint) tokenInformationClass, 
943                                                           safeLocalAllocHandle, 
944                                                           0, 
945                                                           out dwLength);
946             int dwErrorCode = Marshal.GetLastWin32Error();
947             switch (dwErrorCode) {
948             case Win32Native.ERROR_BAD_LENGTH:
949                 // special case for TokenSessionId. Falling through
950             case Win32Native.ERROR_INSUFFICIENT_BUFFER:
951                 // ptrLength is an [In] param to LocalAlloc 
952                 UIntPtr ptrLength = new UIntPtr(dwLength);
953                 safeLocalAllocHandle.Dispose();
954                 safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
955                 if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid) 
956                     throw new OutOfMemoryException();
957                 safeLocalAllocHandle.Initialize(dwLength);
958
959                 result = Win32Native.GetTokenInformation(tokenHandle, 
960                                                          (uint) tokenInformationClass, 
961                                                          safeLocalAllocHandle, 
962                                                          dwLength, 
963                                                          out dwLength);
964                 if (!result)
965                     throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
966                 break;
967             case Win32Native.ERROR_INVALID_HANDLE:
968                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
969             default:
970                 throw new SecurityException(Win32Native.GetMessage(dwErrorCode));
971             }
972             return safeLocalAllocHandle;
973         }
974
975         [System.Security.SecurityCritical]  // auto-generated
976 #if FEATURE_CORRUPTING_EXCEPTIONS
977         [HandleProcessCorruptedStateExceptions] // 
978 #endif // FEATURE_CORRUPTING_EXCEPTIONS
979         private unsafe static SafeAccessTokenHandle KerbS4ULogon (string upn, ref SafeAccessTokenHandle safeTokenHandle)
980         {
981             // source name
982             byte[] sourceName = new byte[] { (byte)'C', (byte)'L', (byte)'R' }; // we set the source name to "CLR".
983
984             // ptrLength is an [In] param to LocalAlloc 
985             UIntPtr ptrLength = new UIntPtr((uint)(sourceName.Length + 1));
986
987             using (SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength)) {
988                 if (pSourceName == null || pSourceName.IsInvalid)
989                     throw new OutOfMemoryException();
990
991                 pSourceName.Initialize((ulong)sourceName.Length + 1);
992                 pSourceName.WriteArray(0, sourceName, 0, sourceName.Length);
993                 Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING(sourceName.Length,
994                                                                                                pSourceName);
995
996                 int status;
997                 SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
998                 SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle;
999                 try {
1000                     Privilege privilege = null;
1001
1002                     RuntimeHelpers.PrepareConstrainedRegions();
1003                     // Try to get an impersonation token.
1004                     try {
1005                         // Try to enable the TCB privilege if possible
1006                         try {
1007                             privilege = new Privilege("SeTcbPrivilege");
1008                             privilege.Enable();
1009                         }
1010                         catch (PrivilegeNotHeldException) { }
1011
1012                         IntPtr dummy = IntPtr.Zero;
1013                         status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
1014                         if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) {
1015                             // We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
1016                             status = Win32Native.LsaConnectUntrusted(ref logonHandle);
1017                         }
1018                     }
1019                     catch {
1020                         // protect against exception filter-based luring attacks
1021                         if (privilege != null)
1022                             privilege.Revert();
1023                         throw;
1024                     }
1025                     finally {
1026                         if (privilege != null)
1027                             privilege.Revert();
1028                     }
1029                     if (status < 0) // non-negative numbers indicate success
1030                         throw GetExceptionFromNtStatus(status);
1031
1032                     // package name ("Kerberos")
1033                     byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
1034                     Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);
1035
1036                     // ptrLength is an [In] param to LocalAlloc 
1037                     ptrLength = new UIntPtr((uint)arrayPackageName.Length);
1038                     using (SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength)) {
1039                         if (pPackageName == null || pPackageName.IsInvalid)
1040                             throw new OutOfMemoryException();
1041                         pPackageName.Initialize((ulong)(uint)arrayPackageName.Length);
1042
1043                         pPackageName.WriteArray(0, arrayPackageName, 0, arrayPackageName.Length);
1044                         Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING(Win32Native.MICROSOFT_KERBEROS_NAME.Length,
1045                                                                                                               pPackageName);
1046                         uint packageId = 0;
1047                         status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId);
1048                         if (status < 0) // non-negative numbers indicate success
1049                             throw GetExceptionFromNtStatus(status);
1050
1051                         // source context
1052                         Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE();
1053                         if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
1054                             throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
1055                         sourceContext.Name = new char[8];
1056                         sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R';
1057
1058                         uint profileSize = 0;
1059                         Win32Native.LUID logonId = new Win32Native.LUID();
1060                         Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS();
1061                         int subStatus = 0;
1062
1063                         //
1064                         // Build the KERB_S4U_LOGON structure.  Note that the LSA expects this entire
1065                         // structure to be contained within the same block of memory, so we need to allocate
1066                         // enough room for both the structure itself and the UPN string in a single buffer
1067                         // and do the marshalling into this buffer by hand.
1068                         //
1069
1070                         byte[] upnBytes = Encoding.Unicode.GetBytes(upn);
1071
1072                         Contract.Assert(Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) % IntPtr.Size == 0, "Potential allignment issue setting up S4U logon buffer");
1073                         uint logonInfoSize = (uint) (Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + upnBytes.Length);
1074                         using (SafeLocalAllocHandle logonInfoBuffer = Win32Native.LocalAlloc(Win32Native.LPTR, new UIntPtr(logonInfoSize))) {
1075                             if (logonInfoBuffer == null || logonInfoBuffer.IsInvalid) {
1076                                 throw new OutOfMemoryException();
1077                             }
1078
1079                             logonInfoBuffer.Initialize((ulong)logonInfoSize);
1080
1081                             // Write the UPN to the end of the serialized buffer
1082                             ulong upnOffset = (ulong)Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON));
1083                             logonInfoBuffer.WriteArray(upnOffset,
1084                                                        upnBytes,
1085                                                        0,
1086                                                        upnBytes.Length);
1087
1088                             unsafe {
1089                                 byte* pLogonInfoBuffer = null;
1090
1091                                 RuntimeHelpers.PrepareConstrainedRegions();
1092                                 try {
1093                                     logonInfoBuffer.AcquirePointer(ref pLogonInfoBuffer);
1094
1095                                     // Setup the KERB_S4U_LOGON structure
1096                                     Win32Native.KERB_S4U_LOGON logonInfo = new Win32Native.KERB_S4U_LOGON();
1097                                     logonInfo.MessageType = (uint)KerbLogonSubmitType.KerbS4ULogon;
1098                                     logonInfo.Flags = 0;
1099
1100                                     // Point the ClientUpn at the UPN written at the end of this buffer
1101                                     logonInfo.ClientUpn = new Win32Native.UNICODE_INTPTR_STRING(upnBytes.Length,
1102                                                                                                 new IntPtr(pLogonInfoBuffer + upnOffset));
1103
1104                                     logonInfoBuffer.Write(0, logonInfo);
1105
1106                                     // logon user
1107                                     status = Win32Native.LsaLogonUser(logonHandle,
1108                                                                       ref Name,
1109                                                                       (uint)SecurityLogonType.Network,
1110                                                                       packageId,
1111                                                                                           new IntPtr(pLogonInfoBuffer),
1112                                                                                           (uint)logonInfoBuffer.ByteLength,
1113                                                                       IntPtr.Zero,
1114                                                                       ref sourceContext,
1115                                                                       ref profile,
1116                                                                       ref profileSize,
1117                                                                       ref logonId,
1118                                                                       ref safeTokenHandle,
1119                                                                       ref quotas,
1120                                                                       ref subStatus);
1121
1122                                     // If both status and substatus are < 0, substatus is preferred.
1123                                     if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
1124                                         status = subStatus;
1125                                     if (status < 0) // non-negative numbers indicate success
1126                                         throw GetExceptionFromNtStatus(status);
1127                                     if (subStatus < 0) // non-negative numbers indicate success
1128                                         throw GetExceptionFromNtStatus(subStatus);
1129                                 }
1130                                 finally {
1131                                     if (pLogonInfoBuffer != null) {
1132                                         logonInfoBuffer.ReleasePointer();
1133                                     }
1134                                 }
1135                             }
1136                         }
1137
1138                         return safeTokenHandle;
1139                     }
1140                 }
1141                 finally {
1142                     if (!logonHandle.IsInvalid)
1143                         logonHandle.Dispose();
1144                     if (!profile.IsInvalid)
1145                         profile.Dispose();
1146                 }
1147             }
1148         }
1149     
1150 #if !FEATURE_CORECLR
1151
1152         [SecuritySafeCritical]
1153         protected WindowsIdentity (WindowsIdentity identity)
1154             : base( identity, null, identity.m_authType, null, null, false )
1155         {
1156             if (identity == null)
1157                 throw new ArgumentNullException("identity");
1158
1159             Contract.EndContractBlock();
1160
1161             bool mustDecrement = false;
1162             RuntimeHelpers.PrepareConstrainedRegions();
1163             try
1164             {
1165                 if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle != SafeAccessTokenHandle.InvalidHandle && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1166                 {
1167                     identity.m_safeTokenHandle.DangerousAddRef(ref mustDecrement);
1168
1169                     if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1170                         CreateFromToken(identity.m_safeTokenHandle.DangerousGetHandle());
1171
1172                     m_authType = identity.m_authType;
1173                     m_isAuthenticated = identity.m_isAuthenticated;
1174                 }
1175             }
1176             finally
1177             {
1178                 if (mustDecrement)
1179                     identity.m_safeTokenHandle.DangerousRelease();
1180             }
1181         }
1182         
1183         [SecurityCritical]
1184         internal IntPtr GetTokenInternal()
1185         {
1186             return m_safeTokenHandle.DangerousGetHandle();
1187         }
1188
1189         [SecurityCritical]
1190         internal WindowsIdentity(ClaimsIdentity claimsIdentity, IntPtr userToken)
1191             : base(claimsIdentity)
1192         {
1193             if (userToken != IntPtr.Zero && userToken.ToInt64() > 0)
1194             {
1195                 CreateFromToken(userToken);
1196             }
1197         }
1198
1199         /// <summary>
1200         /// Returns a new instance of the base, used when serializing the WindowsIdentity.
1201         /// </summary>
1202         internal ClaimsIdentity CloneAsBase()
1203         {
1204             return base.Clone();
1205         }
1206
1207         /// <summary>
1208         /// Returns a new instance of <see cref="WindowsIdentity"/> with values copied from this object.
1209         /// </summary>
1210         public override ClaimsIdentity Clone()
1211         {
1212             return new WindowsIdentity(this);
1213         }
1214
1215         /// <summary>
1216         /// Gets the 'User Claims' from the NTToken that represents this identity
1217         /// </summary>
1218         public virtual IEnumerable<Claim> UserClaims
1219         {
1220             get
1221             {
1222                 InitializeClaims();
1223
1224                 return m_userClaims.AsReadOnly();
1225             }
1226         }
1227
1228         /// <summary>
1229         /// Gets the 'Device Claims' from the NTToken that represents the device the identity is using
1230         /// </summary>
1231         public virtual IEnumerable<Claim> DeviceClaims
1232         {
1233             get
1234             {
1235                 InitializeClaims();
1236
1237                 return m_deviceClaims.AsReadOnly();
1238             }
1239         }
1240
1241         /// <summary>
1242         /// Gets the claims as <see cref="IEnumerable{Claim}"/>, associated with this <see cref="WindowsIdentity"/>.
1243         /// Includes UserClaims and DeviceClaims.
1244         /// </summary>
1245         public override IEnumerable<Claim> Claims
1246         {
1247             get 
1248             {
1249                 if (!m_claimsInitialized)
1250                 {
1251                     InitializeClaims();
1252                 }
1253
1254                 foreach (Claim claim in base.Claims)
1255                     yield return claim;
1256
1257                 foreach (Claim claim in m_userClaims)
1258                     yield return claim;
1259
1260                 foreach (Claim claim in m_deviceClaims)
1261                     yield return claim;
1262             }
1263         }
1264
1265         /// <summary>
1266         /// Intenal method to initialize the claim collection.
1267         /// Lazy init is used so claims are not initialzed until needed
1268         /// </summary>
1269         [SecuritySafeCritical]
1270         void InitializeClaims()
1271         {
1272             if (!m_claimsInitialized)
1273             {
1274                 lock (m_claimsIntiailizedLock)
1275                 {
1276                     if (!m_claimsInitialized)
1277                     {
1278                         m_userClaims = new List<Claim>();
1279                         m_deviceClaims = new List<Claim>();
1280
1281                         if (!String.IsNullOrEmpty(Name))
1282                         {
1283                             //
1284                             // Add the name claim only if the WindowsIdentity.Name is populated
1285                             // WindowsIdentity.Name will be null when it is the fake anonymous user
1286                             // with a token value of IntPtr.Zero
1287                             //
1288                             m_userClaims.Add(new Claim(NameClaimType, Name, ClaimValueTypes.String, m_issuerName, m_issuerName, this));
1289                         }
1290
1291                         // primary sid
1292                         AddPrimarySidClaim(m_userClaims);
1293
1294                         // group sids
1295                         AddGroupSidClaims(m_userClaims);
1296
1297                         // The following TokenInformationClass's were part of the Win8 release
1298                         if (Environment.IsWindows8OrAbove)
1299                         {
1300                             // Device group sids
1301                             AddDeviceGroupSidClaims(m_deviceClaims, TokenInformationClass.TokenDeviceGroups);
1302
1303                             // User token claims
1304                             AddTokenClaims(m_userClaims, TokenInformationClass.TokenUserClaimAttributes, ClaimTypes.WindowsUserClaim);
1305
1306                             // Device token claims
1307                             AddTokenClaims(m_deviceClaims, TokenInformationClass.TokenDeviceClaimAttributes, ClaimTypes.WindowsDeviceClaim);
1308                         }
1309
1310                         m_claimsInitialized = true;
1311                     }
1312                 }
1313             }
1314         }
1315
1316         /// <summary>
1317         /// Creates a collection of SID claims that represent the DeviceSidGroups.
1318         /// </summary>
1319         /// this is SafeCritical as it accesss the NT token.
1320         [SecurityCritical]
1321         void AddDeviceGroupSidClaims(List<Claim> instanceClaims,  TokenInformationClass tokenInformationClass)
1322         {
1323             // special case the anonymous identity.
1324             if (m_safeTokenHandle.IsInvalid)
1325                 return;
1326
1327             SafeLocalAllocHandle safeAllocHandle =  SafeLocalAllocHandle.InvalidHandle;
1328             try
1329             {
1330                 // Retrieve all group sids
1331
1332                 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1333                 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1334                 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1335                 string claimType = null;
1336
1337                 for (int i = 0; i < count; ++i)
1338                 {
1339                     Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1340                     uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1341                     SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1342                     if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1343                     {
1344                         claimType = ClaimTypes.WindowsDeviceGroup;
1345                         Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1346                         claim.Properties.Add(claimType, "");
1347                         instanceClaims.Add(claim);
1348                     }
1349                     else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1350                     {
1351                         claimType = ClaimTypes.DenyOnlyWindowsDeviceGroup;
1352                         Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1353                         claim.Properties.Add(claimType, "");
1354                         instanceClaims.Add(claim);
1355                     }
1356
1357                     pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1358                 }
1359             }
1360             finally
1361             {
1362                 safeAllocHandle.Close();
1363             }
1364         }
1365
1366         /// <summary>
1367         /// Creates a collection of SID claims that represent the users groups.
1368         /// </summary>
1369         /// this is SafeCritical as it accesss the NT token.
1370         [SecurityCritical]
1371         void AddGroupSidClaims(List<Claim> instanceClaims)
1372         {
1373             // special case the anonymous identity.
1374             if (m_safeTokenHandle.IsInvalid)
1375                 return;
1376
1377             SafeLocalAllocHandle safeAllocHandle =  SafeLocalAllocHandle.InvalidHandle;
1378             SafeLocalAllocHandle safeAllocHandlePrimaryGroup =  SafeLocalAllocHandle.InvalidHandle;
1379             try
1380             {
1381                 // Retrieve the primary group sid
1382                 safeAllocHandlePrimaryGroup = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenPrimaryGroup);
1383                 Win32Native.TOKEN_PRIMARY_GROUP primaryGroup = (Win32Native.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(safeAllocHandlePrimaryGroup.DangerousGetHandle(), typeof(Win32Native.TOKEN_PRIMARY_GROUP));
1384                 SecurityIdentifier primaryGroupSid = new SecurityIdentifier(primaryGroup.PrimaryGroup, true);
1385                     
1386                 // only add one primary group sid
1387                 bool foundPrimaryGroupSid = false;
1388
1389                 // Retrieve all group sids, primary group sid is one of them
1390                 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups);
1391                 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1392                 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1393                 for (int i = 0; i < count; ++i)
1394                 {
1395                     Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1396                     uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1397                     SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1398
1399                     if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1400                     {
1401                         if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1402                         {
1403                             instanceClaims.Add(new Claim(ClaimTypes.PrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1404                             foundPrimaryGroupSid = true;
1405                         }
1406                         //Primary group sid generates both regular groupsid claim and primary groupsid claim
1407                         instanceClaims.Add(new Claim(ClaimTypes.GroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1408
1409                     }
1410                     else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1411                     {
1412                         if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1413                         {
1414                             instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1415                             foundPrimaryGroupSid = true;
1416                         }
1417                         //Primary group sid generates both regular groupsid claim and primary groupsid claim
1418                         instanceClaims.Add(new Claim(ClaimTypes.DenyOnlySid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1419                     }
1420                     pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1421                 }
1422             }
1423             finally
1424             {
1425                 safeAllocHandle.Close();
1426                 safeAllocHandlePrimaryGroup.Close();
1427             }
1428         }
1429         
1430         /// <summary>
1431         /// Creates a Windows SID Claim and adds to collection of claims.
1432         /// </summary>
1433         /// this is SafeCritical as it accesss the NT token.        
1434         [SecurityCritical]        
1435         void AddPrimarySidClaim(List<Claim> instanceClaims)
1436         {
1437             // special case the anonymous identity.
1438             if (m_safeTokenHandle.IsInvalid)
1439                 return;
1440
1441             SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1442             try
1443             {
1444                 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser);
1445                 Win32Native.SID_AND_ATTRIBUTES user = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.SID_AND_ATTRIBUTES));
1446                 uint mask = Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1447                
1448                 SecurityIdentifier sid = new SecurityIdentifier(user.Sid, true);
1449
1450                 if (user.Attributes == 0)
1451                 {
1452                     instanceClaims.Add(new Claim(ClaimTypes.PrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1453                 }
1454                 else if ((user.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1455                 {
1456                     instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1457                 }
1458             }
1459             finally
1460             {
1461                 safeAllocHandle.Close();
1462             }
1463         }
1464
1465         [SecurityCritical]
1466         void AddTokenClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass, string propertyValue)
1467         {
1468             // special case the anonymous identity.
1469             if (m_safeTokenHandle.IsInvalid)
1470                 return;
1471
1472             SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1473
1474             try
1475             {
1476                 SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1477                 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1478
1479                 Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION claimAttributes = (Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION));
1480                 // An attribute represents a collection of claims.  Inside each attribute a claim can be multivalued, we create a claim for each value.
1481                 // It is a ragged multi-dimentional array, where each cell can be of different lenghts.
1482                 
1483                 // index into array of claims.
1484                 long offset = 0;
1485                
1486                 for (int attribute = 0; attribute < claimAttributes.AttributeCount; attribute++)
1487                 {
1488                     IntPtr pAttribute = new IntPtr(claimAttributes.Attribute.pAttributeV1.ToInt64() + offset);
1489                     Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1 windowsClaim = (Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1)Marshal.PtrToStructure(pAttribute, typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1));                    
1490                     
1491                     // the switch was written this way, which appears to have multiple for loops, because each item in the ValueCount is of the same ValueType.  This saves the type check each item.
1492                     switch (windowsClaim.ValueType)
1493                     {
1494                         case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
1495                             IntPtr[] stringPointers = new IntPtr[windowsClaim.ValueCount];
1496                             Marshal.Copy(windowsClaim.Values.ppString, stringPointers, 0, (int)windowsClaim.ValueCount);
1497
1498                             for (int item = 0; item < windowsClaim.ValueCount; item++)
1499                             {
1500                                 instanceClaims.Add( new Claim(windowsClaim.Name, Marshal.PtrToStringAuto(stringPointers[item]), ClaimValueTypes.String, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1501                             }
1502                             break;
1503
1504                         case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
1505                             Int64[] intValues = new Int64[windowsClaim.ValueCount];
1506                             Marshal.Copy(windowsClaim.Values.pInt64, intValues, 0, (int)windowsClaim.ValueCount);
1507
1508                             for (int item = 0; item < windowsClaim.ValueCount; item++)
1509                             {
1510                                 instanceClaims.Add(new Claim(windowsClaim.Name, Convert.ToString(intValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1511                             }
1512                             break;
1513
1514
1515                         case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
1516                             Int64[] uintValues = new Int64[windowsClaim.ValueCount];
1517                             Marshal.Copy(windowsClaim.Values.pUint64, uintValues, 0, (int)windowsClaim.ValueCount);
1518
1519                             for (int item = 0; item < windowsClaim.ValueCount; item++)
1520                             {
1521                                 instanceClaims.Add( new Claim(windowsClaim.Name, Convert.ToString((UInt64)uintValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.UInteger64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1522                             }
1523                             break;
1524
1525                         case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
1526                             Int64[] boolValues = new Int64[windowsClaim.ValueCount];
1527                             Marshal.Copy(windowsClaim.Values.pUint64, boolValues, 0, (int)windowsClaim.ValueCount);
1528
1529                             for (int item = 0; item < windowsClaim.ValueCount; item++)
1530                             {
1531                                 instanceClaims.Add(new Claim(windowsClaim.Name,
1532                                                   ((UInt64)boolValues[item] == 0 ? Convert.ToString(false, CultureInfo.InvariantCulture) : Convert.ToString(true, CultureInfo.InvariantCulture)),
1533                                                   ClaimValueTypes.Boolean, 
1534                                                   m_issuerName, 
1535                                                   m_issuerName, 
1536                                                   this, 
1537                                                   propertyValue, 
1538                                                   string.Empty));
1539                             }
1540                             break;
1541
1542
1543                         // These claim types are defined in the structure found in winnt.h, but I haven't received confirmation (may  2011) that they are supported and are not enabled.
1544
1545                         //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN:
1546                         //    break;
1547
1548                         //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
1549                         //    break;
1550
1551                         //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
1552                         //    break;
1553
1554                     }
1555
1556                     offset += Marshal.SizeOf(windowsClaim);
1557                 }
1558             }
1559             finally
1560             {
1561                 safeAllocHandle.Close();
1562             }
1563         }
1564
1565     }
1566 #endif
1567
1568     [Serializable]
1569     internal enum KerbLogonSubmitType : int {
1570         KerbInteractiveLogon = 2,
1571         KerbSmartCardLogon = 6,
1572         KerbWorkstationUnlockLogon = 7,
1573         KerbSmartCardUnlockLogon = 8,
1574         KerbProxyLogon = 9,
1575         KerbTicketLogon = 10,
1576         KerbTicketUnlockLogon = 11,
1577         KerbS4ULogon = 12
1578     }
1579
1580     [Serializable]
1581     internal enum SecurityLogonType : int {
1582         Interactive = 2,
1583         Network,
1584         Batch,
1585         Service,
1586         Proxy,
1587         Unlock
1588     }
1589
1590     [Serializable]
1591     internal enum TokenType : int {
1592         TokenPrimary = 1,
1593         TokenImpersonation
1594     }
1595
1596     [Serializable]
1597     internal enum TokenInformationClass : int {
1598         TokenUser = 1,
1599         TokenGroups,
1600         TokenPrivileges,
1601         TokenOwner,
1602         TokenPrimaryGroup,
1603         TokenDefaultDacl,
1604         TokenSource,
1605         TokenType,
1606         TokenImpersonationLevel,
1607         TokenStatistics,
1608         TokenRestrictedSids,
1609         TokenSessionId,
1610         TokenGroupsAndPrivileges,
1611         TokenSessionReference,
1612         TokenSandBoxInert,
1613         TokenAuditPolicy,
1614         TokenOrigin,
1615         TokenElevationType,
1616         TokenLinkedToken,
1617         TokenElevation,
1618         TokenHasRestrictions,
1619         TokenAccessInformation,
1620         TokenVirtualizationAllowed,
1621         TokenVirtualizationEnabled,
1622         TokenIntegrityLevel,
1623         TokenUIAccess,
1624         TokenMandatoryPolicy,
1625         TokenLogonSid,
1626         TokenIsAppContainer,
1627         TokenCapabilities,
1628         TokenAppContainerSid,
1629         TokenAppContainerNumber,
1630         TokenUserClaimAttributes,
1631         TokenDeviceClaimAttributes,
1632         TokenRestrictedUserClaimAttributes,
1633         TokenRestrictedDeviceClaimAttributes,
1634         TokenDeviceGroups,
1635         TokenRestrictedDeviceGroups,
1636         MaxTokenInfoClass  // MaxTokenInfoClass should always be the last enum
1637     }
1638 }