Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Security / Principal / WindowsIdentity.cs / 1407647 / WindowsIdentity.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// [....]
//
//
// WindowsIdentity.cs
//
// Representation of a process/thread token.
//
namespace System.Security.Principal
{
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
#if FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime.ExceptionServices;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime.Serialization;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum WindowsAccountType {
Normal = 0,
Guest = 1,
System = 2,
Anonymous = 3
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum TokenImpersonationLevel {
None = 0,
Anonymous = 1,
Identification = 2,
Impersonation = 3,
Delegation = 4
}
[Serializable]
[Flags]
[System.Runtime.InteropServices.ComVisible(true)]
public enum TokenAccessLevels {
AssignPrimary = 0x00000001,
Duplicate = 0x00000002,
Impersonate = 0x00000004,
Query = 0x00000008,
QuerySource = 0x00000010,
AdjustPrivileges = 0x00000020,
AdjustGroups = 0x00000040,
AdjustDefault = 0x00000080,
AdjustSessionId = 0x00000100,
Read = 0x00020000 | Query,
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
AllAccess = 0x000F0000 |
AssignPrimary |
Duplicate |
Impersonate |
Query |
QuerySource |
AdjustPrivileges |
AdjustGroups |
AdjustDefault |
AdjustSessionId,
MaximumAllowed = 0x02000000
}
// Keep in [....] with vm\comprincipal.h
internal enum WinSecurityContext {
Thread = 1, // OpenAsSelf = false
Process = 2, // OpenAsSelf = true
Both = 3 // OpenAsSelf = true, then OpenAsSelf = false
}
internal enum ImpersonationQueryResult {
Impersonated = 0, // current thread is impersonated
NotImpersonated = 1, // current thread is not impersonated
Failed = 2 // failed to query
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class WindowsIdentity : IIdentity, ISerializable, IDeserializationCallback, IDisposable {
[System.Security.SecurityCritical] // auto-generated
static SafeTokenHandle s_invalidTokenHandle = SafeTokenHandle.InvalidHandle;
private string m_name = null;
private SecurityIdentifier m_owner = null;
private SecurityIdentifier m_user = null;
private object m_groups = null;
[System.Security.SecurityCritical] // auto-generated
private SafeTokenHandle m_safeTokenHandle = SafeTokenHandle.InvalidHandle;
private string m_authType = null;
private int m_isAuthenticated = -1;
private TokenImpersonationLevel? m_impersonationLevel;
//
// Constructors.
//
[System.Security.SecuritySafeCritical] // auto-generated
static WindowsIdentity()
{
}
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity () {}
[System.Security.SecurityCritical] // auto-generated
internal WindowsIdentity (SafeTokenHandle safeTokenHandle) : this (safeTokenHandle.DangerousGetHandle(), null, -1) {
GC.KeepAlive(safeTokenHandle);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken) : this (userToken, null, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type) : this (userToken, type, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType) : this (userToken, type, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
: this (userToken, type, isAuthenticated ? 1 : 0) {}
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity (IntPtr userToken, string authType, int isAuthenticated) {
CreateFromToken(userToken);
m_authType = authType;
m_isAuthenticated = isAuthenticated;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
private void CreateFromToken (IntPtr userToken) {
if (userToken == IntPtr.Zero)
throw new ArgumentException(Environment.GetResourceString("Argument_TokenZero"));
Contract.EndContractBlock();
// Find out if the specified token is a valid.
uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
bool result = Win32Native.GetTokenInformation(userToken, (uint) TokenInformationClass.TokenType,
SafeLocalAllocHandle.InvalidHandle, 0, out dwLength);
if (Marshal.GetLastWin32Error() == Win32Native.ERROR_INVALID_HANDLE)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
if (!Win32Native.DuplicateHandle(Win32Native.GetCurrentProcess(),
userToken,
Win32Native.GetCurrentProcess(),
ref m_safeTokenHandle,
0,
true,
Win32Native.DUPLICATE_SAME_ACCESS))
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (string sUserPrincipalName) : this (sUserPrincipalName, null) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (string sUserPrincipalName, string type) {
KerbS4ULogon(sUserPrincipalName, ref m_safeTokenHandle);
}
//
// We cannot make sure the token will stay alive
// until it is being deserialized in another AppDomain. We do not have a way to capture
// the state of a token (just a pointer to kernel memory) and re-construct it later
// and even if we did (via calling NtQueryInformationToken and relying on the token undocumented
// format), constructing a token requires TCB privilege. We need to address the "serializable"
// nature of WindowsIdentity since it is not obvious that can be achieved at all.
//
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (SerializationInfo info, StreamingContext context) : this(info)
{
}
// This is a copy of the serialization constructor above but without the
// security demand that's slow and breaks partial trust scenarios
// without an expensive assert in place in the remoting code. Instead we
// special case this class and call the private constructor directly
// (changing the demand above is considered a breaking change, even
// though nobody else should have been using a serialization constructor
// directly).
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity(SerializationInfo info) {
IntPtr userToken = (IntPtr) info.GetValue("m_userToken", typeof(IntPtr));
if (userToken != IntPtr.Zero)
CreateFromToken(userToken);
}
///
[System.Security.SecurityCritical] // auto-generated_required
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {
info.AddValue("m_userToken", m_safeTokenHandle.DangerousGetHandle());
}
///
void IDeserializationCallback.OnDeserialization (Object sender) {}
//
// Factory methods.
//
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent () {
return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent (bool ifImpersonating) {
return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, ifImpersonating);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess) {
return GetCurrentInternal(desiredAccess, false);
}
// GetAnonymous() is used heavily in ASP.NET requests as a dummy identity to indicate
// the request is anonymous. It does not represent a real process or thread token so
// it cannot impersonate or do anything useful. Note this identity does not represent the
// usual concept of an anonymous token, and the name is simply misleading but we cannot change it now.
[System.Security.SecuritySafeCritical] // auto-generated
public static WindowsIdentity GetAnonymous () {
return new WindowsIdentity();
}
//
// Properties.
//
public string AuthenticationType {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// If this is an anonymous identity, return an empty string
if (m_safeTokenHandle.IsInvalid)
return String.Empty;
if (m_authType == null) {
Win32Native.LUID authId = GetLogonAuthId(m_safeTokenHandle);
if (authId.LowPart == Win32Native.ANONYMOUS_LOGON_LUID)
return String.Empty; // no authentication, just return an empty string
SafeLsaReturnBufferHandle pLogonSessionData = SafeLsaReturnBufferHandle.InvalidHandle;
try {
int status = Win32Native.LsaGetLogonSessionData(ref authId, ref pLogonSessionData);
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
pLogonSessionData.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.SECURITY_LOGON_SESSION_DATA)));
Win32Native.SECURITY_LOGON_SESSION_DATA logonSessionData = pLogonSessionData.Read(0);
return Marshal.PtrToStringUni(logonSessionData.AuthenticationPackage.Buffer);
}
finally {
if (!pLogonSessionData.IsInvalid)
pLogonSessionData.Dispose();
}
}
return m_authType;
}
}
[ComVisible(false)]
public TokenImpersonationLevel ImpersonationLevel {
[System.Security.SecuritySafeCritical] // auto-generated
get {
if (!m_impersonationLevel.HasValue) {
m_impersonationLevel = TokenImpersonationLevel.None;
// If this is an anonymous identity
if (m_safeTokenHandle.IsInvalid) {
m_impersonationLevel = TokenImpersonationLevel.Anonymous;
}
else {
TokenType tokenType = (TokenType)GetTokenInformation(TokenInformationClass.TokenType);
if (tokenType == TokenType.TokenPrimary) {
m_impersonationLevel = TokenImpersonationLevel.None; // primary token;
}
else {
/// This is an impersonation token, get the impersonation level
int level = GetTokenInformation(TokenInformationClass.TokenImpersonationLevel);
m_impersonationLevel = (TokenImpersonationLevel)level + 1;
}
}
}
return m_impersonationLevel.Value;
}
}
public virtual bool IsAuthenticated {
get {
if (m_isAuthenticated == -1) {
// There is a known bug where this approach will not work correctly for domain guests (will return false
// instead of true). But this is a corner-case that is not very interesting.
WindowsPrincipal wp = new WindowsPrincipal(this);
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_AUTHENTICATED_USER_RID});
m_isAuthenticated = wp.IsInRole(sid) ? 1 : 0;
}
return m_isAuthenticated == 1;
}
}
//
// IsGuest, IsSystem and IsAnonymous are maintained for compatibility reasons. It is always
// possible to extract this same information from the User SID property and the new
// (and more general) methods defined in the SID class (IsWellKnown, etc...).
//
public virtual bool IsGuest {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return false;
WindowsPrincipal principal = new WindowsPrincipal(this);
return principal.IsInRole(WindowsBuiltInRole.Guest);
}
}
public virtual bool IsSystem {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return false;
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_LOCAL_SYSTEM_RID});
return (this.User == sid);
}
}
public virtual bool IsAnonymous {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return true;
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_ANONYMOUS_LOGON_RID});
return (this.User == sid);
}
}
public virtual string Name {
[System.Security.SecuritySafeCritical] // auto-generated
get {
return GetName();
}
}
[System.Security.SecurityCritical] // auto-generated
[DynamicSecurityMethodAttribute()]
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
internal String GetName()
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return String.Empty;
if (m_name == null)
{
// revert thread impersonation for the duration of the call to get the name.
using (SafeRevertToSelf(ref stackMark))
{
NTAccount ntAccount = this.User.Translate(typeof(NTAccount)) as NTAccount;
m_name = ntAccount.ToString();
}
}
return m_name;
}
[ComVisible(false)]
public SecurityIdentifier Owner {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_owner == null) {
using (SafeLocalAllocHandle tokenOwner = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenOwner)) {
m_owner = new SecurityIdentifier(tokenOwner.Read(0), true);
}
}
return m_owner;
}
}
[ComVisible(false)]
public SecurityIdentifier User {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_user == null) {
using (SafeLocalAllocHandle tokenUser = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser)) {
m_user = new SecurityIdentifier(tokenUser.Read(0), true);
}
}
return m_user;
}
}
public IdentityReferenceCollection Groups {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_groups == null) {
IdentityReferenceCollection groups = new IdentityReferenceCollection();
using (SafeLocalAllocHandle pGroups = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups)) {
uint groupCount = pGroups.Read(0);
// Work-around bug on WS03 that only populates the GroupCount field of TOKEN_GROUPS if the count is 0
// In that situation, attempting to read the entire TOKEN_GROUPS structure will lead to InsufficientBuffer exception
// since the field is only 4 bytes long (uint only, for GroupCount), but we try to read more (including the pointer to GroupDetails).
if (groupCount != 0)
{
Win32Native.TOKEN_GROUPS tokenGroups = pGroups.Read(0);
Win32Native.SID_AND_ATTRIBUTES[] groupDetails = new Win32Native.SID_AND_ATTRIBUTES[tokenGroups.GroupCount];
pGroups.ReadArray((uint)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups").ToInt32(),
groupDetails,
0,
groupDetails.Length);
foreach (Win32Native.SID_AND_ATTRIBUTES group in groupDetails)
{
// Ignore disabled, logon ID, and deny-only groups.
uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED) {
groups.Add(new SecurityIdentifier(group.Sid, true ));
}
}
}
}
Interlocked.CompareExchange(ref m_groups, groups, null);
}
return m_groups as IdentityReferenceCollection;
}
}
//
// Note this property does not duplicate the token. This is also the same as V1/Everett behaviour.
//
public virtual IntPtr Token {
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
return m_safeTokenHandle.DangerousGetHandle();
}
}
//
// Public methods.
//
[System.Security.SecuritySafeCritical] // auto-generated
[DynamicSecurityMethodAttribute()]
[ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public virtual WindowsImpersonationContext Impersonate ()
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Impersonate(ref stackMark);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode)]
[DynamicSecurityMethodAttribute()]
[ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public static WindowsImpersonationContext Impersonate (IntPtr userToken)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
if (userToken == IntPtr.Zero)
return SafeRevertToSelf(ref stackMark);
WindowsIdentity wi = new WindowsIdentity(userToken, null, -1);
return wi.Impersonate(ref stackMark);
}
[System.Security.SecurityCritical] // auto-generated
internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
if (m_safeTokenHandle.IsInvalid)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));
return SafeImpersonate(m_safeTokenHandle, this, ref stackMark);
}
[System.Security.SecuritySafeCritical] // auto-generated
[ComVisible(false)]
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
m_safeTokenHandle.Dispose();
}
m_name = null;
m_owner = null;
m_user = null;
}
[System.Security.SecuritySafeCritical] // auto-generated
[ComVisible(false)]
public void Dispose() {
Dispose(true);
}
//
// internal.
//
internal SafeTokenHandle TokenHandle {
[System.Security.SecurityCritical] // auto-generated
get {
return m_safeTokenHandle;
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
internal static WindowsImpersonationContext SafeRevertToSelf(ref StackCrawlMark stackMark)
{
return SafeImpersonate(s_invalidTokenHandle, null, ref stackMark);
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static WindowsImpersonationContext SafeImpersonate (SafeTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark)
{
bool isImpersonating;
int hr = 0;
SafeTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr);
if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
throw new SecurityException(Win32Native.GetMessage(hr));
// Set the SafeTokenHandle on the FSD:
FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
if (secObj == null)
{
// Security: REQ_SQ flag is missing. Bad compiler ?
// This can happen when you create delegates over functions that need the REQ_SQ
throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) );
}
WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
hr = Win32.RevertToSelf();
if (hr < 0)
Environment.FailFast(Win32Native.GetMessage(hr));
// update identity on the thread
UpdateThreadWI(wi);
secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle));
} else {
hr = Win32.RevertToSelf();
if (hr < 0)
Environment.FailFast(Win32Native.GetMessage(hr));
hr = Win32.ImpersonateLoggedOnUser(userToken);
if (hr < 0) {
context.Undo();
throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
}
UpdateThreadWI(wi);
secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle));
}
return context;
}
[System.Security.SecurityCritical] // auto-generated
internal static WindowsIdentity GetCurrentThreadWI()
{
return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextNoCreate());
}
internal static void UpdateThreadWI(WindowsIdentity wi)
{
// Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
SecurityContext sc = SecurityContext.GetCurrentSecurityContextNoCreate();
if (wi != null && sc == null) {
// create a new security context on the thread
sc = new SecurityContext();
Thread.CurrentThread.ExecutionContext.SecurityContext = sc;
}
if (sc != null) // null-check needed here since we will not create an sc if wi is null
{
sc.WindowsIdentity = wi;
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) {
int hr = 0;
bool isImpersonating;
SafeTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
if (safeTokenHandle == null || safeTokenHandle.IsInvalid) {
// either we wanted only ThreadToken - return null
if (threadOnly && !isImpersonating)
return null;
// or there was an error
throw new SecurityException(Win32Native.GetMessage(hr));
}
WindowsIdentity wi = new WindowsIdentity();
wi.m_safeTokenHandle.Dispose();
wi.m_safeTokenHandle = safeTokenHandle;
return wi;
}
//
// private.
//
private static int GetHRForWin32Error (int dwLastError) {
if ((dwLastError & 0x80000000) == 0x80000000)
return dwLastError;
else
return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
}
[System.Security.SecurityCritical] // auto-generated
private static Exception GetExceptionFromNtStatus (int status) {
if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
return new UnauthorizedAccessException();
if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
return new OutOfMemoryException();
int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
private static SafeTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
isImpersonating = true;
SafeTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
// No impersonation
isImpersonating = false;
if (!threadOnly)
safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
}
return safeTokenHandle;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
private static SafeTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) {
hr = 0;
SafeTokenHandle safeTokenHandle;
if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle))
hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
return safeTokenHandle;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static SafeTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
SafeTokenHandle safeTokenHandle;
hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle);
return safeTokenHandle;
}
///
/// Get a property from the current token
///
[System.Security.SecurityCritical] // auto-generated
private T GetTokenInformation(TokenInformationClass tokenInformationClass) where T : struct{
Contract.Assert(!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed, "!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed");
using (SafeLocalAllocHandle information = GetTokenInformation(m_safeTokenHandle, tokenInformationClass)) {
Contract.Assert(information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T)),
"information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T))");
return information.Read(0);
}
}
//
// QueryImpersonation used to test if the current thread is impersonated.
// This method doesn't return the thread token (WindowsIdentity).
// Although GetCurrentInternal can be used to perform the same test but
// QueryImpersonation is optimized for the perf.
//
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static ImpersonationQueryResult QueryImpersonation() {
SafeTokenHandle safeTokenHandle = null;
int hr = Win32.OpenThreadToken(TokenAccessLevels.Query, WinSecurityContext.Thread, out safeTokenHandle);
if (safeTokenHandle != null) {
Contract.Assert(hr == 0, "[WindowsIdentity..QueryImpersonation] - hr == 0");
safeTokenHandle.Close();
return ImpersonationQueryResult.Impersonated;
}
if (hr == GetHRForWin32Error(Win32Native.ERROR_ACCESS_DENIED)) {
// thread is impersonated because the thread was there (and we failed to open it).
return ImpersonationQueryResult.Impersonated;
}
if (hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
// definitely not impersonating
return ImpersonationQueryResult.NotImpersonated;
}
// Unexpected failure.
return ImpersonationQueryResult.Failed;
}
[System.Security.SecurityCritical] // auto-generated
private static Win32Native.LUID GetLogonAuthId (SafeTokenHandle safeTokenHandle) {
using (SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics)) {
Win32Native.TOKEN_STATISTICS statistics = pStatistics.Read(0);
return statistics.AuthenticationId;
}
}
[System.Security.SecurityCritical] // auto-generated
private static SafeLocalAllocHandle GetTokenInformation (SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass) {
SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
bool result = Win32Native.GetTokenInformation(tokenHandle,
(uint) tokenInformationClass,
safeLocalAllocHandle,
0,
out dwLength);
int dwErrorCode = Marshal.GetLastWin32Error();
switch (dwErrorCode) {
case Win32Native.ERROR_BAD_LENGTH:
// special case for TokenSessionId. Falling through
case Win32Native.ERROR_INSUFFICIENT_BUFFER:
// ptrLength is an [In] param to LocalAlloc
IntPtr ptrLength = new IntPtr(dwLength);
safeLocalAllocHandle.Dispose();
safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
throw new OutOfMemoryException();
safeLocalAllocHandle.Initialize(dwLength);
result = Win32Native.GetTokenInformation(tokenHandle,
(uint) tokenInformationClass,
safeLocalAllocHandle,
dwLength,
out dwLength);
if (!result)
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
break;
case Win32Native.ERROR_INVALID_HANDLE:
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
default:
throw new SecurityException(Win32Native.GetMessage(dwErrorCode));
}
return safeLocalAllocHandle;
}
[System.Security.SecurityCritical] // auto-generated
#if FEATURE_CORRUPTING_EXCEPTIONS
[HandleProcessCorruptedStateExceptions] //
#endif // FEATURE_CORRUPTING_EXCEPTIONS
private unsafe static SafeTokenHandle KerbS4ULogon (string upn, ref SafeTokenHandle safeTokenHandle) {
// source name
byte[] sourceName = new byte[] {(byte) 'C', (byte) 'L', (byte) 'R'}; // we set the source name to "CLR".
// ptrLength is an [In] param to LocalAlloc
IntPtr ptrLength = new IntPtr((uint) (sourceName.Length + 1));
using (SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength)) {
if (pSourceName == null || pSourceName.IsInvalid)
throw new OutOfMemoryException();
pSourceName.Initialize((ulong)sourceName.Length + 1);
pSourceName.WriteArray(0, sourceName, 0, sourceName.Length);
Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING(sourceName.Length,
pSourceName);
int status;
SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle;
try {
Privilege privilege = null;
RuntimeHelpers.PrepareConstrainedRegions();
// Try to get an impersonation token.
try {
// Try to enable the TCB privilege if possible
try {
privilege = new Privilege("SeTcbPrivilege");
privilege.Enable();
}
catch (PrivilegeNotHeldException) { }
IntPtr dummy = IntPtr.Zero;
status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) {
// We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
status = Win32Native.LsaConnectUntrusted(ref logonHandle);
}
}
catch {
// protect against exception filter-based luring attacks
if (privilege != null)
privilege.Revert();
throw;
}
finally {
if (privilege != null)
privilege.Revert();
}
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
// package name ("Kerberos")
byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);
// ptrLength is an [In] param to LocalAlloc
ptrLength = new IntPtr((uint) arrayPackageName.Length);
using (SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength)) {
if (pPackageName == null || pPackageName.IsInvalid)
throw new OutOfMemoryException();
pPackageName.Initialize((ulong)arrayPackageName.Length);
pPackageName.WriteArray(0, arrayPackageName, 0, arrayPackageName.Length);
Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING(Win32Native.MICROSOFT_KERBEROS_NAME.Length,
pPackageName);
uint packageId = 0;
status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId);
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
// source context
Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE();
if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
sourceContext.Name = new char[8];
sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R';
uint profileSize = 0;
Win32Native.LUID logonId = new Win32Native.LUID();
Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS();
int subStatus = 0;
//
// Build the KERB_S4U_LOGON structure. Note that the LSA expects this entire
// structure to be contained within the same block of memory, so we need to allocate
// enough room for both the structure itself and the UPN string in a single buffer
// and do the marshalling into this buffer by hand.
//
byte[] upnBytes = Encoding.Unicode.GetBytes(upn);
Contract.Assert(Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) % IntPtr.Size == 0, "Potential allignment issue setting up S4U logon buffer");
int logonInfoSize = Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + upnBytes.Length;
using (SafeLocalAllocHandle logonInfoBuffer = Win32Native.LocalAlloc(Win32Native.LPTR, new IntPtr(logonInfoSize))) {
if (logonInfoBuffer == null || logonInfoBuffer.IsInvalid) {
throw new OutOfMemoryException();
}
logonInfoBuffer.Initialize((ulong)logonInfoSize);
// Write the UPN to the end of the serialized buffer
ulong upnOffset = (ulong)Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON));
logonInfoBuffer.WriteArray(upnOffset,
upnBytes,
0,
upnBytes.Length);
unsafe {
byte* pLogonInfoBuffer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try {
logonInfoBuffer.AcquirePointer(ref pLogonInfoBuffer);
// Setup the KERB_S4U_LOGON structure
Win32Native.KERB_S4U_LOGON logonInfo = new Win32Native.KERB_S4U_LOGON();
logonInfo.MessageType = (uint)KerbLogonSubmitType.KerbS4ULogon;
logonInfo.Flags = 0;
// Point the ClientUpn at the UPN written at the end of this buffer
logonInfo.ClientUpn = new Win32Native.UNICODE_INTPTR_STRING(upnBytes.Length,
new IntPtr(pLogonInfoBuffer + upnOffset));
logonInfoBuffer.Write(0, logonInfo);
// logon user
status = Win32Native.LsaLogonUser(logonHandle,
ref Name,
(uint) SecurityLogonType.Network,
packageId,
new IntPtr(pLogonInfoBuffer),
(uint)logonInfoBuffer.ByteLength,
IntPtr.Zero,
ref sourceContext,
ref profile,
ref profileSize,
ref logonId,
ref safeTokenHandle,
ref quotas,
ref subStatus);
// If both status and substatus are < 0, substatus is preferred.
if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
status = subStatus;
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
if (subStatus < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(subStatus);
}
finally {
if (pLogonInfoBuffer != null) {
logonInfoBuffer.ReleasePointer();
}
}
}
}
return safeTokenHandle;
}
}
finally {
if (!logonHandle.IsInvalid)
logonHandle.Dispose();
if (!profile.IsInvalid)
profile.Dispose();
}
}
}
}
[Serializable]
internal enum KerbLogonSubmitType : int {
KerbInteractiveLogon = 2,
KerbSmartCardLogon = 6,
KerbWorkstationUnlockLogon = 7,
KerbSmartCardUnlockLogon = 8,
KerbProxyLogon = 9,
KerbTicketLogon = 10,
KerbTicketUnlockLogon = 11,
KerbS4ULogon = 12
}
[Serializable]
internal enum SecurityLogonType : int {
Interactive = 2,
Network,
Batch,
Service,
Proxy,
Unlock
}
[Serializable]
internal enum TokenType : int {
TokenPrimary = 1,
TokenImpersonation
}
[Serializable]
internal enum TokenInformationClass : int {
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// [....]
//
//
// WindowsIdentity.cs
//
// Representation of a process/thread token.
//
namespace System.Security.Principal
{
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
#if FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime.ExceptionServices;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime.Serialization;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum WindowsAccountType {
Normal = 0,
Guest = 1,
System = 2,
Anonymous = 3
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum TokenImpersonationLevel {
None = 0,
Anonymous = 1,
Identification = 2,
Impersonation = 3,
Delegation = 4
}
[Serializable]
[Flags]
[System.Runtime.InteropServices.ComVisible(true)]
public enum TokenAccessLevels {
AssignPrimary = 0x00000001,
Duplicate = 0x00000002,
Impersonate = 0x00000004,
Query = 0x00000008,
QuerySource = 0x00000010,
AdjustPrivileges = 0x00000020,
AdjustGroups = 0x00000040,
AdjustDefault = 0x00000080,
AdjustSessionId = 0x00000100,
Read = 0x00020000 | Query,
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
AllAccess = 0x000F0000 |
AssignPrimary |
Duplicate |
Impersonate |
Query |
QuerySource |
AdjustPrivileges |
AdjustGroups |
AdjustDefault |
AdjustSessionId,
MaximumAllowed = 0x02000000
}
// Keep in [....] with vm\comprincipal.h
internal enum WinSecurityContext {
Thread = 1, // OpenAsSelf = false
Process = 2, // OpenAsSelf = true
Both = 3 // OpenAsSelf = true, then OpenAsSelf = false
}
internal enum ImpersonationQueryResult {
Impersonated = 0, // current thread is impersonated
NotImpersonated = 1, // current thread is not impersonated
Failed = 2 // failed to query
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class WindowsIdentity : IIdentity, ISerializable, IDeserializationCallback, IDisposable {
[System.Security.SecurityCritical] // auto-generated
static SafeTokenHandle s_invalidTokenHandle = SafeTokenHandle.InvalidHandle;
private string m_name = null;
private SecurityIdentifier m_owner = null;
private SecurityIdentifier m_user = null;
private object m_groups = null;
[System.Security.SecurityCritical] // auto-generated
private SafeTokenHandle m_safeTokenHandle = SafeTokenHandle.InvalidHandle;
private string m_authType = null;
private int m_isAuthenticated = -1;
private TokenImpersonationLevel? m_impersonationLevel;
//
// Constructors.
//
[System.Security.SecuritySafeCritical] // auto-generated
static WindowsIdentity()
{
}
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity () {}
[System.Security.SecurityCritical] // auto-generated
internal WindowsIdentity (SafeTokenHandle safeTokenHandle) : this (safeTokenHandle.DangerousGetHandle(), null, -1) {
GC.KeepAlive(safeTokenHandle);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken) : this (userToken, null, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type) : this (userToken, type, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType) : this (userToken, type, -1) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
: this (userToken, type, isAuthenticated ? 1 : 0) {}
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity (IntPtr userToken, string authType, int isAuthenticated) {
CreateFromToken(userToken);
m_authType = authType;
m_isAuthenticated = isAuthenticated;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
private void CreateFromToken (IntPtr userToken) {
if (userToken == IntPtr.Zero)
throw new ArgumentException(Environment.GetResourceString("Argument_TokenZero"));
Contract.EndContractBlock();
// Find out if the specified token is a valid.
uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
bool result = Win32Native.GetTokenInformation(userToken, (uint) TokenInformationClass.TokenType,
SafeLocalAllocHandle.InvalidHandle, 0, out dwLength);
if (Marshal.GetLastWin32Error() == Win32Native.ERROR_INVALID_HANDLE)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
if (!Win32Native.DuplicateHandle(Win32Native.GetCurrentProcess(),
userToken,
Win32Native.GetCurrentProcess(),
ref m_safeTokenHandle,
0,
true,
Win32Native.DUPLICATE_SAME_ACCESS))
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (string sUserPrincipalName) : this (sUserPrincipalName, null) {}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (string sUserPrincipalName, string type) {
KerbS4ULogon(sUserPrincipalName, ref m_safeTokenHandle);
}
//
// We cannot make sure the token will stay alive
// until it is being deserialized in another AppDomain. We do not have a way to capture
// the state of a token (just a pointer to kernel memory) and re-construct it later
// and even if we did (via calling NtQueryInformationToken and relying on the token undocumented
// format), constructing a token requires TCB privilege. We need to address the "serializable"
// nature of WindowsIdentity since it is not obvious that can be achieved at all.
//
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public WindowsIdentity (SerializationInfo info, StreamingContext context) : this(info)
{
}
// This is a copy of the serialization constructor above but without the
// security demand that's slow and breaks partial trust scenarios
// without an expensive assert in place in the remoting code. Instead we
// special case this class and call the private constructor directly
// (changing the demand above is considered a breaking change, even
// though nobody else should have been using a serialization constructor
// directly).
[System.Security.SecurityCritical] // auto-generated
private WindowsIdentity(SerializationInfo info) {
IntPtr userToken = (IntPtr) info.GetValue("m_userToken", typeof(IntPtr));
if (userToken != IntPtr.Zero)
CreateFromToken(userToken);
}
///
[System.Security.SecurityCritical] // auto-generated_required
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {
info.AddValue("m_userToken", m_safeTokenHandle.DangerousGetHandle());
}
///
void IDeserializationCallback.OnDeserialization (Object sender) {}
//
// Factory methods.
//
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent () {
return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent (bool ifImpersonating) {
return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, ifImpersonating);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess) {
return GetCurrentInternal(desiredAccess, false);
}
// GetAnonymous() is used heavily in ASP.NET requests as a dummy identity to indicate
// the request is anonymous. It does not represent a real process or thread token so
// it cannot impersonate or do anything useful. Note this identity does not represent the
// usual concept of an anonymous token, and the name is simply misleading but we cannot change it now.
[System.Security.SecuritySafeCritical] // auto-generated
public static WindowsIdentity GetAnonymous () {
return new WindowsIdentity();
}
//
// Properties.
//
public string AuthenticationType {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// If this is an anonymous identity, return an empty string
if (m_safeTokenHandle.IsInvalid)
return String.Empty;
if (m_authType == null) {
Win32Native.LUID authId = GetLogonAuthId(m_safeTokenHandle);
if (authId.LowPart == Win32Native.ANONYMOUS_LOGON_LUID)
return String.Empty; // no authentication, just return an empty string
SafeLsaReturnBufferHandle pLogonSessionData = SafeLsaReturnBufferHandle.InvalidHandle;
try {
int status = Win32Native.LsaGetLogonSessionData(ref authId, ref pLogonSessionData);
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
pLogonSessionData.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.SECURITY_LOGON_SESSION_DATA)));
Win32Native.SECURITY_LOGON_SESSION_DATA logonSessionData = pLogonSessionData.Read(0);
return Marshal.PtrToStringUni(logonSessionData.AuthenticationPackage.Buffer);
}
finally {
if (!pLogonSessionData.IsInvalid)
pLogonSessionData.Dispose();
}
}
return m_authType;
}
}
[ComVisible(false)]
public TokenImpersonationLevel ImpersonationLevel {
[System.Security.SecuritySafeCritical] // auto-generated
get {
if (!m_impersonationLevel.HasValue) {
m_impersonationLevel = TokenImpersonationLevel.None;
// If this is an anonymous identity
if (m_safeTokenHandle.IsInvalid) {
m_impersonationLevel = TokenImpersonationLevel.Anonymous;
}
else {
TokenType tokenType = (TokenType)GetTokenInformation(TokenInformationClass.TokenType);
if (tokenType == TokenType.TokenPrimary) {
m_impersonationLevel = TokenImpersonationLevel.None; // primary token;
}
else {
/// This is an impersonation token, get the impersonation level
int level = GetTokenInformation(TokenInformationClass.TokenImpersonationLevel);
m_impersonationLevel = (TokenImpersonationLevel)level + 1;
}
}
}
return m_impersonationLevel.Value;
}
}
public virtual bool IsAuthenticated {
get {
if (m_isAuthenticated == -1) {
// There is a known bug where this approach will not work correctly for domain guests (will return false
// instead of true). But this is a corner-case that is not very interesting.
WindowsPrincipal wp = new WindowsPrincipal(this);
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_AUTHENTICATED_USER_RID});
m_isAuthenticated = wp.IsInRole(sid) ? 1 : 0;
}
return m_isAuthenticated == 1;
}
}
//
// IsGuest, IsSystem and IsAnonymous are maintained for compatibility reasons. It is always
// possible to extract this same information from the User SID property and the new
// (and more general) methods defined in the SID class (IsWellKnown, etc...).
//
public virtual bool IsGuest {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return false;
WindowsPrincipal principal = new WindowsPrincipal(this);
return principal.IsInRole(WindowsBuiltInRole.Guest);
}
}
public virtual bool IsSystem {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return false;
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_LOCAL_SYSTEM_RID});
return (this.User == sid);
}
}
public virtual bool IsAnonymous {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return true;
SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
new int[] {Win32Native.SECURITY_ANONYMOUS_LOGON_RID});
return (this.User == sid);
}
}
public virtual string Name {
[System.Security.SecuritySafeCritical] // auto-generated
get {
return GetName();
}
}
[System.Security.SecurityCritical] // auto-generated
[DynamicSecurityMethodAttribute()]
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
internal String GetName()
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return String.Empty;
if (m_name == null)
{
// revert thread impersonation for the duration of the call to get the name.
using (SafeRevertToSelf(ref stackMark))
{
NTAccount ntAccount = this.User.Translate(typeof(NTAccount)) as NTAccount;
m_name = ntAccount.ToString();
}
}
return m_name;
}
[ComVisible(false)]
public SecurityIdentifier Owner {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_owner == null) {
using (SafeLocalAllocHandle tokenOwner = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenOwner)) {
m_owner = new SecurityIdentifier(tokenOwner.Read(0), true);
}
}
return m_owner;
}
}
[ComVisible(false)]
public SecurityIdentifier User {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_user == null) {
using (SafeLocalAllocHandle tokenUser = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser)) {
m_user = new SecurityIdentifier(tokenUser.Read(0), true);
}
}
return m_user;
}
}
public IdentityReferenceCollection Groups {
[System.Security.SecuritySafeCritical] // auto-generated
get {
// special case the anonymous identity.
if (m_safeTokenHandle.IsInvalid)
return null;
if (m_groups == null) {
IdentityReferenceCollection groups = new IdentityReferenceCollection();
using (SafeLocalAllocHandle pGroups = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups)) {
uint groupCount = pGroups.Read(0);
// Work-around bug on WS03 that only populates the GroupCount field of TOKEN_GROUPS if the count is 0
// In that situation, attempting to read the entire TOKEN_GROUPS structure will lead to InsufficientBuffer exception
// since the field is only 4 bytes long (uint only, for GroupCount), but we try to read more (including the pointer to GroupDetails).
if (groupCount != 0)
{
Win32Native.TOKEN_GROUPS tokenGroups = pGroups.Read(0);
Win32Native.SID_AND_ATTRIBUTES[] groupDetails = new Win32Native.SID_AND_ATTRIBUTES[tokenGroups.GroupCount];
pGroups.ReadArray((uint)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups").ToInt32(),
groupDetails,
0,
groupDetails.Length);
foreach (Win32Native.SID_AND_ATTRIBUTES group in groupDetails)
{
// Ignore disabled, logon ID, and deny-only groups.
uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED) {
groups.Add(new SecurityIdentifier(group.Sid, true ));
}
}
}
}
Interlocked.CompareExchange(ref m_groups, groups, null);
}
return m_groups as IdentityReferenceCollection;
}
}
//
// Note this property does not duplicate the token. This is also the same as V1/Everett behaviour.
//
public virtual IntPtr Token {
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
return m_safeTokenHandle.DangerousGetHandle();
}
}
//
// Public methods.
//
[System.Security.SecuritySafeCritical] // auto-generated
[DynamicSecurityMethodAttribute()]
[ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public virtual WindowsImpersonationContext Impersonate ()
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Impersonate(ref stackMark);
}
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode)]
[DynamicSecurityMethodAttribute()]
[ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public static WindowsImpersonationContext Impersonate (IntPtr userToken)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
if (userToken == IntPtr.Zero)
return SafeRevertToSelf(ref stackMark);
WindowsIdentity wi = new WindowsIdentity(userToken, null, -1);
return wi.Impersonate(ref stackMark);
}
[System.Security.SecurityCritical] // auto-generated
internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
if (m_safeTokenHandle.IsInvalid)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));
return SafeImpersonate(m_safeTokenHandle, this, ref stackMark);
}
[System.Security.SecuritySafeCritical] // auto-generated
[ComVisible(false)]
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
m_safeTokenHandle.Dispose();
}
m_name = null;
m_owner = null;
m_user = null;
}
[System.Security.SecuritySafeCritical] // auto-generated
[ComVisible(false)]
public void Dispose() {
Dispose(true);
}
//
// internal.
//
internal SafeTokenHandle TokenHandle {
[System.Security.SecurityCritical] // auto-generated
get {
return m_safeTokenHandle;
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
internal static WindowsImpersonationContext SafeRevertToSelf(ref StackCrawlMark stackMark)
{
return SafeImpersonate(s_invalidTokenHandle, null, ref stackMark);
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static WindowsImpersonationContext SafeImpersonate (SafeTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark)
{
bool isImpersonating;
int hr = 0;
SafeTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr);
if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
throw new SecurityException(Win32Native.GetMessage(hr));
// Set the SafeTokenHandle on the FSD:
FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
if (secObj == null)
{
// Security: REQ_SQ flag is missing. Bad compiler ?
// This can happen when you create delegates over functions that need the REQ_SQ
throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) );
}
WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
hr = Win32.RevertToSelf();
if (hr < 0)
Environment.FailFast(Win32Native.GetMessage(hr));
// update identity on the thread
UpdateThreadWI(wi);
secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle));
} else {
hr = Win32.RevertToSelf();
if (hr < 0)
Environment.FailFast(Win32Native.GetMessage(hr));
hr = Win32.ImpersonateLoggedOnUser(userToken);
if (hr < 0) {
context.Undo();
throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
}
UpdateThreadWI(wi);
secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.TokenHandle));
}
return context;
}
[System.Security.SecurityCritical] // auto-generated
internal static WindowsIdentity GetCurrentThreadWI()
{
return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextNoCreate());
}
internal static void UpdateThreadWI(WindowsIdentity wi)
{
// Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
SecurityContext sc = SecurityContext.GetCurrentSecurityContextNoCreate();
if (wi != null && sc == null) {
// create a new security context on the thread
sc = new SecurityContext();
Thread.CurrentThread.ExecutionContext.SecurityContext = sc;
}
if (sc != null) // null-check needed here since we will not create an sc if wi is null
{
sc.WindowsIdentity = wi;
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) {
int hr = 0;
bool isImpersonating;
SafeTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
if (safeTokenHandle == null || safeTokenHandle.IsInvalid) {
// either we wanted only ThreadToken - return null
if (threadOnly && !isImpersonating)
return null;
// or there was an error
throw new SecurityException(Win32Native.GetMessage(hr));
}
WindowsIdentity wi = new WindowsIdentity();
wi.m_safeTokenHandle.Dispose();
wi.m_safeTokenHandle = safeTokenHandle;
return wi;
}
//
// private.
//
private static int GetHRForWin32Error (int dwLastError) {
if ((dwLastError & 0x80000000) == 0x80000000)
return dwLastError;
else
return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
}
[System.Security.SecurityCritical] // auto-generated
private static Exception GetExceptionFromNtStatus (int status) {
if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
return new UnauthorizedAccessException();
if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
return new OutOfMemoryException();
int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
private static SafeTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
isImpersonating = true;
SafeTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
// No impersonation
isImpersonating = false;
if (!threadOnly)
safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
}
return safeTokenHandle;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
private static SafeTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) {
hr = 0;
SafeTokenHandle safeTokenHandle;
if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle))
hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
return safeTokenHandle;
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static SafeTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
SafeTokenHandle safeTokenHandle;
hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle);
return safeTokenHandle;
}
///
/// Get a property from the current token
///
[System.Security.SecurityCritical] // auto-generated
private T GetTokenInformation(TokenInformationClass tokenInformationClass) where T : struct{
Contract.Assert(!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed, "!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed");
using (SafeLocalAllocHandle information = GetTokenInformation(m_safeTokenHandle, tokenInformationClass)) {
Contract.Assert(information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T)),
"information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T))");
return information.Read(0);
}
}
//
// QueryImpersonation used to test if the current thread is impersonated.
// This method doesn't return the thread token (WindowsIdentity).
// Although GetCurrentInternal can be used to perform the same test but
// QueryImpersonation is optimized for the perf.
//
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
internal static ImpersonationQueryResult QueryImpersonation() {
SafeTokenHandle safeTokenHandle = null;
int hr = Win32.OpenThreadToken(TokenAccessLevels.Query, WinSecurityContext.Thread, out safeTokenHandle);
if (safeTokenHandle != null) {
Contract.Assert(hr == 0, "[WindowsIdentity..QueryImpersonation] - hr == 0");
safeTokenHandle.Close();
return ImpersonationQueryResult.Impersonated;
}
if (hr == GetHRForWin32Error(Win32Native.ERROR_ACCESS_DENIED)) {
// thread is impersonated because the thread was there (and we failed to open it).
return ImpersonationQueryResult.Impersonated;
}
if (hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
// definitely not impersonating
return ImpersonationQueryResult.NotImpersonated;
}
// Unexpected failure.
return ImpersonationQueryResult.Failed;
}
[System.Security.SecurityCritical] // auto-generated
private static Win32Native.LUID GetLogonAuthId (SafeTokenHandle safeTokenHandle) {
using (SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics)) {
Win32Native.TOKEN_STATISTICS statistics = pStatistics.Read(0);
return statistics.AuthenticationId;
}
}
[System.Security.SecurityCritical] // auto-generated
private static SafeLocalAllocHandle GetTokenInformation (SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass) {
SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
bool result = Win32Native.GetTokenInformation(tokenHandle,
(uint) tokenInformationClass,
safeLocalAllocHandle,
0,
out dwLength);
int dwErrorCode = Marshal.GetLastWin32Error();
switch (dwErrorCode) {
case Win32Native.ERROR_BAD_LENGTH:
// special case for TokenSessionId. Falling through
case Win32Native.ERROR_INSUFFICIENT_BUFFER:
// ptrLength is an [In] param to LocalAlloc
IntPtr ptrLength = new IntPtr(dwLength);
safeLocalAllocHandle.Dispose();
safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
throw new OutOfMemoryException();
safeLocalAllocHandle.Initialize(dwLength);
result = Win32Native.GetTokenInformation(tokenHandle,
(uint) tokenInformationClass,
safeLocalAllocHandle,
dwLength,
out dwLength);
if (!result)
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
break;
case Win32Native.ERROR_INVALID_HANDLE:
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
default:
throw new SecurityException(Win32Native.GetMessage(dwErrorCode));
}
return safeLocalAllocHandle;
}
[System.Security.SecurityCritical] // auto-generated
#if FEATURE_CORRUPTING_EXCEPTIONS
[HandleProcessCorruptedStateExceptions] //
#endif // FEATURE_CORRUPTING_EXCEPTIONS
private unsafe static SafeTokenHandle KerbS4ULogon (string upn, ref SafeTokenHandle safeTokenHandle) {
// source name
byte[] sourceName = new byte[] {(byte) 'C', (byte) 'L', (byte) 'R'}; // we set the source name to "CLR".
// ptrLength is an [In] param to LocalAlloc
IntPtr ptrLength = new IntPtr((uint) (sourceName.Length + 1));
using (SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength)) {
if (pSourceName == null || pSourceName.IsInvalid)
throw new OutOfMemoryException();
pSourceName.Initialize((ulong)sourceName.Length + 1);
pSourceName.WriteArray(0, sourceName, 0, sourceName.Length);
Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING(sourceName.Length,
pSourceName);
int status;
SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle;
try {
Privilege privilege = null;
RuntimeHelpers.PrepareConstrainedRegions();
// Try to get an impersonation token.
try {
// Try to enable the TCB privilege if possible
try {
privilege = new Privilege("SeTcbPrivilege");
privilege.Enable();
}
catch (PrivilegeNotHeldException) { }
IntPtr dummy = IntPtr.Zero;
status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) {
// We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
status = Win32Native.LsaConnectUntrusted(ref logonHandle);
}
}
catch {
// protect against exception filter-based luring attacks
if (privilege != null)
privilege.Revert();
throw;
}
finally {
if (privilege != null)
privilege.Revert();
}
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
// package name ("Kerberos")
byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);
// ptrLength is an [In] param to LocalAlloc
ptrLength = new IntPtr((uint) arrayPackageName.Length);
using (SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength)) {
if (pPackageName == null || pPackageName.IsInvalid)
throw new OutOfMemoryException();
pPackageName.Initialize((ulong)arrayPackageName.Length);
pPackageName.WriteArray(0, arrayPackageName, 0, arrayPackageName.Length);
Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING(Win32Native.MICROSOFT_KERBEROS_NAME.Length,
pPackageName);
uint packageId = 0;
status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId);
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
// source context
Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE();
if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
sourceContext.Name = new char[8];
sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R';
uint profileSize = 0;
Win32Native.LUID logonId = new Win32Native.LUID();
Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS();
int subStatus = 0;
//
// Build the KERB_S4U_LOGON structure. Note that the LSA expects this entire
// structure to be contained within the same block of memory, so we need to allocate
// enough room for both the structure itself and the UPN string in a single buffer
// and do the marshalling into this buffer by hand.
//
byte[] upnBytes = Encoding.Unicode.GetBytes(upn);
Contract.Assert(Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) % IntPtr.Size == 0, "Potential allignment issue setting up S4U logon buffer");
int logonInfoSize = Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + upnBytes.Length;
using (SafeLocalAllocHandle logonInfoBuffer = Win32Native.LocalAlloc(Win32Native.LPTR, new IntPtr(logonInfoSize))) {
if (logonInfoBuffer == null || logonInfoBuffer.IsInvalid) {
throw new OutOfMemoryException();
}
logonInfoBuffer.Initialize((ulong)logonInfoSize);
// Write the UPN to the end of the serialized buffer
ulong upnOffset = (ulong)Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON));
logonInfoBuffer.WriteArray(upnOffset,
upnBytes,
0,
upnBytes.Length);
unsafe {
byte* pLogonInfoBuffer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try {
logonInfoBuffer.AcquirePointer(ref pLogonInfoBuffer);
// Setup the KERB_S4U_LOGON structure
Win32Native.KERB_S4U_LOGON logonInfo = new Win32Native.KERB_S4U_LOGON();
logonInfo.MessageType = (uint)KerbLogonSubmitType.KerbS4ULogon;
logonInfo.Flags = 0;
// Point the ClientUpn at the UPN written at the end of this buffer
logonInfo.ClientUpn = new Win32Native.UNICODE_INTPTR_STRING(upnBytes.Length,
new IntPtr(pLogonInfoBuffer + upnOffset));
logonInfoBuffer.Write(0, logonInfo);
// logon user
status = Win32Native.LsaLogonUser(logonHandle,
ref Name,
(uint) SecurityLogonType.Network,
packageId,
new IntPtr(pLogonInfoBuffer),
(uint)logonInfoBuffer.ByteLength,
IntPtr.Zero,
ref sourceContext,
ref profile,
ref profileSize,
ref logonId,
ref safeTokenHandle,
ref quotas,
ref subStatus);
// If both status and substatus are < 0, substatus is preferred.
if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
status = subStatus;
if (status < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(status);
if (subStatus < 0) // non-negative numbers indicate success
throw GetExceptionFromNtStatus(subStatus);
}
finally {
if (pLogonInfoBuffer != null) {
logonInfoBuffer.ReleasePointer();
}
}
}
}
return safeTokenHandle;
}
}
finally {
if (!logonHandle.IsInvalid)
logonHandle.Dispose();
if (!profile.IsInvalid)
profile.Dispose();
}
}
}
}
[Serializable]
internal enum KerbLogonSubmitType : int {
KerbInteractiveLogon = 2,
KerbSmartCardLogon = 6,
KerbWorkstationUnlockLogon = 7,
KerbSmartCardUnlockLogon = 8,
KerbProxyLogon = 9,
KerbTicketLogon = 10,
KerbTicketUnlockLogon = 11,
KerbS4ULogon = 12
}
[Serializable]
internal enum SecurityLogonType : int {
Interactive = 2,
Network,
Batch,
Service,
Proxy,
Unlock
}
[Serializable]
internal enum TokenType : int {
TokenPrimary = 1,
TokenImpersonation
}
[Serializable]
internal enum TokenInformationClass : int {
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Timer.cs
- SctClaimSerializer.cs
- HttpRequest.cs
- ScriptComponentDescriptor.cs
- LabelAutomationPeer.cs
- AuthenticationServiceManager.cs
- FlowLayoutPanel.cs
- Control.cs
- AsyncResult.cs
- MemberExpressionHelper.cs
- PromptEventArgs.cs
- TableSectionStyle.cs
- SafeNativeMethods.cs
- PermissionAttributes.cs
- MasterPageBuildProvider.cs
- ClientSettingsSection.cs
- SynchronizationFilter.cs
- NullableDoubleSumAggregationOperator.cs
- Decoder.cs
- WindowsEditBoxRange.cs
- AstTree.cs
- ActivityDesignerResources.cs
- MbpInfo.cs
- CommaDelimitedStringAttributeCollectionConverter.cs
- XmlChildEnumerator.cs
- TypedTableBase.cs
- XPathDocument.cs
- EventData.cs
- NativeMethods.cs
- CommandEventArgs.cs
- TableLayoutRowStyleCollection.cs
- OutKeywords.cs
- SharedPerformanceCounter.cs
- BehaviorEditorPart.cs
- TypeUnloadedException.cs
- RealizationDrawingContextWalker.cs
- SafeFileMappingHandle.cs
- RichTextBox.cs
- Repeater.cs
- CompleteWizardStep.cs
- SchemaAttDef.cs
- ChtmlFormAdapter.cs
- WebServiceReceive.cs
- Track.cs
- AndCondition.cs
- ServiceModelExtensionElement.cs
- ValidatorUtils.cs
- PersonalizablePropertyEntry.cs
- ChameleonKey.cs
- PersonalizationProviderCollection.cs
- HMACMD5.cs
- RijndaelManaged.cs
- TextLine.cs
- XPathDocumentBuilder.cs
- CodeComment.cs
- Win32PrintDialog.cs
- BitmapSizeOptions.cs
- serverconfig.cs
- HostedTcpTransportManager.cs
- XmlSchemaSimpleTypeList.cs
- StreamGeometryContext.cs
- PropertyPath.cs
- DrawingAttributeSerializer.cs
- FlowNode.cs
- Codec.cs
- ObjectConverter.cs
- PersonalizationProvider.cs
- BindToObject.cs
- RightsManagementLicense.cs
- StateWorkerRequest.cs
- RolePrincipal.cs
- Property.cs
- DataBinder.cs
- XmlBindingWorker.cs
- RunInstallerAttribute.cs
- TransformerTypeCollection.cs
- ProxyWebPartManager.cs
- WsiProfilesElement.cs
- BufferModeSettings.cs
- SmtpDigestAuthenticationModule.cs
- WindowsEditBox.cs
- StrokeRenderer.cs
- DependencyObjectProvider.cs
- SimpleHandlerBuildProvider.cs
- WorkflowEnvironment.cs
- ProcessModelInfo.cs
- WebPartCancelEventArgs.cs
- FixedDocumentPaginator.cs
- XmlSchemaAttributeGroup.cs
- CodeEntryPointMethod.cs
- VisualBrush.cs
- ImageAnimator.cs
- TextEmbeddedObject.cs
- EmptyEnumerator.cs
- DataBindingCollection.cs
- InteropBitmapSource.cs
- CryptoStream.cs
- WorkflowDesigner.cs
- DrawingVisualDrawingContext.cs
- LocalizationCodeDomSerializer.cs