internal static partial bool DuplicateTokenEx( SafeTokenHandle ExistingTokenHandle, TokenAccessLevels DesiredAccess, IntPtr TokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, System.Security.Principal.TokenType TokenType, ref SafeTokenHandle?DuplicateTokenHandle);
internal static int SetThreadToken(SafeTokenHandle?hToken) { int hr = 0; if (!Interop.Advapi32.SetThreadToken(IntPtr.Zero, hToken)) { hr = Marshal.GetHRForLastWin32Error(); } return(hr); }
private static unsafe void SetPrivilege(string privilegeName, int attrib) { // this is only a "pseudo handle" to the current process - no need to close it later SafeProcessHandle processHandle = Interop.Kernel32.GetCurrentProcess(); SafeTokenHandle?hToken = null; try { // get the process token so we can adjust the privilege on it. We DO need to // close the token when we're done with it. if (!Interop.Advapi32.OpenProcessToken(processHandle, Interop.Kernel32.HandleOptions.TOKEN_ADJUST_PRIVILEGES, out hToken)) { throw new Win32Exception(); } if (!Interop.Advapi32.LookupPrivilegeValue(null, privilegeName, out Interop.Advapi32.LUID luid)) { throw new Win32Exception(); } Interop.Advapi32.TOKEN_PRIVILEGE tp; tp.PrivilegeCount = 1; tp.Privileges.Luid = luid; tp.Privileges.Attributes = (uint)attrib; Interop.Advapi32.AdjustTokenPrivileges(hToken, false, &tp, 0, null, null); // AdjustTokenPrivileges can return true even if it failed to // set the privilege, so we need to use GetLastError if (Marshal.GetLastWin32Error() != Interop.Errors.ERROR_SUCCESS) { throw new Win32Exception(); } } finally { if (hToken != null) { hToken.Dispose(); } } }
static unsafe ProcessManager() { // In order to query information (OpenProcess) on some protected processes // like csrss, we need SeDebugPrivilege privilege. // After removing the dependency on Performance Counter, we don't have a chance // to run the code in CLR performance counter to ask for this privilege. // So we will try to get the privilege here. // We could fail if the user account doesn't have right to do this, but that's fair. Interop.Advapi32.LUID luid; if (!Interop.Advapi32.LookupPrivilegeValue(null, Interop.Advapi32.SeDebugPrivilege, out luid)) { return; } SafeTokenHandle?tokenHandle = null; try { if (!Interop.Advapi32.OpenProcessToken( Interop.Kernel32.GetCurrentProcess(), Interop.Kernel32.HandleOptions.TOKEN_ADJUST_PRIVILEGES, out tokenHandle)) { return; } Interop.Advapi32.TOKEN_PRIVILEGE tp; tp.PrivilegeCount = 1; tp.Privileges.Luid = luid; tp.Privileges.Attributes = Interop.Advapi32.SEPrivileges.SE_PRIVILEGE_ENABLED; // AdjustTokenPrivileges can return true even if it didn't succeed (when ERROR_NOT_ALL_ASSIGNED is returned). Interop.Advapi32.AdjustTokenPrivileges(tokenHandle, false, &tp, 0, null, null); } finally { if (tokenHandle != null) { tokenHandle.Dispose(); } } }
private static bool GetCurrentProcessIntegrity(out int integrityLevel) { integrityLevel = 0; SafeTokenHandle?safeTokenHandle = null; var num = IntPtr.Zero; try { if (!Process.GetCurrentProcess().SafeHandle.OpenAccessToken(8, out safeTokenHandle)) { return(false); } if (!safeTokenHandle.GetIntegrityLevelTokenSize(out var tokenSize)) { return(false); } num = Marshal.AllocHGlobal((int)tokenSize); if (num == IntPtr.Zero) { return(false); } if (!safeTokenHandle.GetIntegrityLevelToken(tokenSize, num)) { return(false); } integrityLevel = num.GetIntegrityLevel(); return(true); } finally { safeTokenHandle?.CloseTokenHandleIfOpened(); if (num != IntPtr.Zero) { Marshal.FreeHGlobal(num); } } }
private void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { if (this.threadHandle != null) { this.threadHandle.Dispose(); this.threadHandle = null !; } } if (this.isImpersonating) { Interop.Advapi32.RevertToSelf(); } this.disposed = true; }
public TlsContents() { int error = 0; int cachingError = 0; bool success = true; if (processHandle.IsInvalid) { lock (syncRoot) { if (processHandle.IsInvalid) { SafeTokenHandle localProcessHandle; if (false == Interop.Advapi32.OpenProcessToken( Interop.Kernel32.GetCurrentProcess(), TokenAccessLevels.Duplicate, out localProcessHandle)) { cachingError = Marshal.GetLastWin32Error(); success = false; } processHandle = localProcessHandle; } } } try { // // Open the thread token; if there is no thread token, get one from // the process token by impersonating self. // SafeTokenHandle?threadHandleBefore = this.threadHandle; error = OpenThreadToken( TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges, WinSecurityContext.Process, out this.threadHandle); unchecked { error &= ~(int)0x80070000; } if (error != 0) { if (success == true) { this.threadHandle = threadHandleBefore; if (error != Interop.Errors.ERROR_NO_TOKEN) { success = false; } System.Diagnostics.Debug.Assert(this.isImpersonating == false, "Incorrect isImpersonating state"); if (success == true) { error = 0; if (false == Interop.Advapi32.DuplicateTokenEx( processHandle, TokenAccessLevels.Impersonate | TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges, IntPtr.Zero, Interop.Advapi32.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, System.Security.Principal.TokenType.TokenImpersonation, ref this.threadHandle)) { error = Marshal.GetLastWin32Error(); success = false; } } if (success == true) { error = SetThreadToken(this.threadHandle); unchecked { error &= ~(int)0x80070000; } if (error != 0) { success = false; } } if (success == true) { this.isImpersonating = true; } } else { error = cachingError; } } else { success = true; } } finally { if (!success) { Dispose(); } } if (error == Interop.Errors.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } else if (error == Interop.Errors.ERROR_ACCESS_DENIED || error == Interop.Errors.ERROR_CANT_OPEN_ANONYMOUS) { throw new UnauthorizedAccessException(); } else if (error != 0) { System.Diagnostics.Debug.Fail($"WindowsIdentity.GetCurrentThreadToken() failed with unrecognized error code {error}"); throw new InvalidOperationException(); } }
/// <summary> /// The function gets the integrity level of the current process. Integrity level is only /// available on Windows Vista and newer operating systems, thus GetProcessIntegrityLevel /// throws a C++ exception if it is called on systems prior to Windows Vista. /// </summary> /// <returns> /// Returns the integrity level of the current process. It is usually one of these values: /// /// SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used by processes /// started by the Anonymous group. Blocks most write access. (SID: S-1-16-0x0) /// /// SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by Protected Mode /// Internet Explorer. Blocks write acess to most objects (such as files and registry keys) /// on the system. (SID: S-1-16-0x1000) /// /// SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is used by normal /// applications being launched while UAC is enabled. (SID: S-1-16-0x2000) /// /// SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used by administrative /// applications launched through elevation when UAC is enabled, or normal applications if /// UAC is disabled and the user is an administrator. (SID: S-1-16-0x3000) /// /// SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is used by services and /// other system-level applications (such as Wininit, Winlogon, Smss, etc.) (SID: S-1-16-0x4000) /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception with the /// last error code. /// </exception> public static int GetProcessIntegrityLevel() { int IL = -1; SafeTokenHandle?hToken = null; int cbTokenIL = 0; IntPtr pTokenIL = IntPtr.Zero; try { // Open the access token of the current process with TOKEN_QUERY. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // Then we must query the size of the integrity level information associated with // the token. Note that we expect GetTokenInformation to return false with the // ERROR_INSUFFICIENT_BUFFER error code because we've given it a null buffer. On // exit cbTokenIL will tell the size of the group information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, IntPtr.Zero, 0, out cbTokenIL)) { int error = Marshal.GetLastWin32Error(); if (error != NativeMethods.ERROR_INSUFFICIENT_BUFFER) { // When the process is run on operating systems prior to Windows Vista, // GetTokenInformation returns false with the ERROR_INVALID_PARAMETER error // code because TokenIntegrityLevel is not supported on those OS's. throw new Win32Exception(error); } } // Now we allocate a buffer for the integrity level information. pTokenIL = Marshal.AllocHGlobal(cbTokenIL); if (pTokenIL == IntPtr.Zero) { throw new Win32Exception(); } // Now we ask for the integrity level information again. This may fail if an // administrator has added this account to an additional group between our first // call to GetTokenInformation and this one. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenIL, cbTokenIL, out cbTokenIL)) { throw new Win32Exception(); } // Marshal the TOKEN_MANDATORY_LABEL struct from native to .NET object. var tokenMandatoryLabel = Marshal.PtrToStructure(pTokenIL, typeof(TOKEN_MANDATORY_LABEL)); if (tokenMandatoryLabel is TOKEN_MANDATORY_LABEL tokenIL) { // Integrity Level SIDs are in the form of S-1-16-0xXXXX. (e.g. S-1-16-0x1000 // stands for low integrity level SID). There is one and only one subauthority. IntPtr pIL = NativeMethods.GetSidSubAuthority(tokenIL.Label.Sid, 0); IL = Marshal.ReadInt32(pIL); } else { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new NullReferenceException(nameof(tokenMandatoryLabel)); #pragma warning restore CA1303 // Do not pass literals as localized parameters } } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); } if (pTokenIL != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenIL); } } return(IL); }
/// <summary> /// The function checks whether the primary access token of the process belongs to user /// account that is a member of the local Administrators group, even if it currently is not elevated. /// </summary> /// <returns> /// Returns true if the primary access token of the process belongs to user account that is /// a member of the local Administrators group. Returns false if the token does not. /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception with the /// last error code. /// </exception> internal static bool IsUserInAdminGroup() { bool fInAdminGroup = false; SafeTokenHandle?hToken = null; SafeTokenHandle?hTokenToCheck = null; IntPtr pElevationType = IntPtr.Zero; IntPtr pLinkedToken = IntPtr.Zero; int cbSize = 0; try { // Open the access token of the current process for query and duplicate. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_DUPLICATE, out hToken)) { throw new Win32Exception(); } // Determine whether system is running Windows Vista or later operating systems // (major version >= 6) because they support linked tokens, but previous versions // (major version < 6) do not. if (Environment.OSVersion.Version.Major >= 6) { // Running Windows Vista or later (major version >= 6). Determine token type: // limited, elevated, or default. // Allocate a buffer for the elevation type information. cbSize = sizeof(TOKEN_ELEVATION_TYPE); pElevationType = Marshal.AllocHGlobal(cbSize); if (pElevationType == IntPtr.Zero) { throw new Win32Exception(); } // Retrieve token elevation type information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize)) { throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET. TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(pElevationType); // If limited, get the linked elevated token for further check. if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) { // Allocate a buffer for the linked token. cbSize = IntPtr.Size; pLinkedToken = Marshal.AllocHGlobal(cbSize); if (pLinkedToken == IntPtr.Zero) { throw new Win32Exception(); } // Get the linked token. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSize, out cbSize)) { throw new Win32Exception(); } // Marshal the linked token value from native to .NET. IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken); hTokenToCheck = new SafeTokenHandle(hLinkedToken); } } // CheckTokenMembership requires an impersonation token. If we just got a linked // token, it already is an impersonation token. If we did not get a linked token, // duplicate the original into an impersonation token for CheckTokenMembership. if (hTokenToCheck == null) { if (!NativeMethods.DuplicateToken(hToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, out hTokenToCheck)) { throw new Win32Exception(); } } // Check if the token to be checked contains admin SID. using WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle()); WindowsPrincipal principal = new WindowsPrincipal(id); fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator); } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); } if (hTokenToCheck != null) { hTokenToCheck.Close(); } if (pElevationType != IntPtr.Zero) { Marshal.FreeHGlobal(pElevationType); } if (pLinkedToken != IntPtr.Zero) { Marshal.FreeHGlobal(pLinkedToken); } } return(fInAdminGroup); }
/// <summary> /// The function gets the elevation information of the current process. It dictates whether /// the process is elevated or not. Token elevation is only available on Windows Vista and /// newer operating systems, thus IsProcessElevated throws a C++ exception if it is called /// on systems prior to Windows Vista. It is not appropriate to use this function to /// determine whether a process is run as administartor. /// </summary> /// <returns>Returns true if the process is elevated. Returns false if it is not.</returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception with the /// last error code. /// </exception> /// <remarks> /// TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation type /// (TokenElevationTypeDefault / TokenElevationTypeLimited / /// TokenElevationTypeFull) of the process. It is different from TokenElevation in that, /// when UAC is turned off, elevation type always returns TokenElevationTypeDefault even /// though the process is elevated (Integrity Level == High). In other words, it is not safe /// to say if the process is elevated based on elevation type. Instead, we should use TokenElevation. /// </remarks> internal static bool IsProcessElevated() { bool fIsElevated = false; SafeTokenHandle?hToken = null; int cbTokenElevation = 0; IntPtr pTokenElevation = IntPtr.Zero; try { // Open the access token of the current process with TOKEN_QUERY. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // Allocate a buffer for the elevation information. cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION)); pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation); if (pTokenElevation == IntPtr.Zero) { throw new Win32Exception(); } // Retrieve token elevation information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation, cbTokenElevation, out cbTokenElevation)) { // When the process is run on operating systems prior to Windows Vista, // GetTokenInformation returns false with the error code ERROR_INVALID_PARAMETER // because TokenElevation is not supported on those operating systems. throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION struct from native to .NET object. //TOKEN_ELEVATION elevation = (TOKEN_ELEVATION) // Marshal the TOKEN_MANDATORY_LABEL struct from native to .NET object. var elevation = Marshal.PtrToStructure(pTokenElevation, typeof(TOKEN_ELEVATION)); if (elevation is TOKEN_ELEVATION elevationToken) { // TOKEN_ELEVATION.TokenIsElevated is a non-zero value if the token has elevated // privileges; otherwise, a zero value. fIsElevated = (elevationToken.TokenIsElevated != 0); } else { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new NullReferenceException(nameof(elevation)); #pragma warning restore CA1303 // Do not pass literals as localized parameters } } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); } if (pTokenElevation != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenElevation); } } return(fIsElevated); }
internal static partial bool SetThreadToken( IntPtr ThreadHandle, SafeTokenHandle?hToken);
internal static extern bool SetThreadToken(IntPtr ThreadHandle, SafeTokenHandle?hToken);
/// <summary> /// Logs on the user with the given credentials as an interactive user. /// </summary> /// <param name="userName">Name of the user.</param> /// <param name="domain">The domain.</param> /// <param name="password">The password.</param> /// <param name="userToken">The user token.</param> /// <returns> /// 0 if the function succeeds, a HRESULT of the last error if the function fails. /// </returns> public static int LogOnInteractiveUser([CanBeNull] string?userName, [CanBeNull] string?domain, [CanBeNull] string?password, [CanBeNull] out SafeTokenHandle?userToken) { ParseUserDomain(ref userName, ref domain); if (NativeMethods.LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out var pUserToken)) { userToken = new SafeTokenHandle(pUserToken); return(0); } userToken = null; var error = Marshal.GetHRForLastWin32Error(); return(error == 0 ? E_FAIL : error); }
/// <summary> /// Logs on the user with the given credentials as an interactive user. /// </summary> /// <param name="credential">The credential.</param> /// <param name="userToken">The user token.</param> /// <returns> /// 0 if the function succeeds, a HRESULT of the last error if the function fails. /// </returns> public static int LogOnInteractiveUser([NotNull] this NetworkCredential credential, [CanBeNull] out SafeTokenHandle?userToken) { return(LogOnInteractiveUser(credential.UserName, credential.Domain, credential.Password, out userToken)); }
internal static int OpenThreadToken(TokenAccessLevels dwDesiredAccess, WinSecurityContext dwOpenAs, out SafeTokenHandle?phThreadToken) { int hr = 0; bool openAsSelf = true; if (dwOpenAs == WinSecurityContext.Thread) { openAsSelf = false; } if (!Interop.Advapi32.OpenThreadToken((IntPtr)(-2), dwDesiredAccess, openAsSelf, out phThreadToken)) { if (dwOpenAs == WinSecurityContext.Both) { openAsSelf = false; hr = 0; if (!Interop.Advapi32.OpenThreadToken((IntPtr)(-2), dwDesiredAccess, openAsSelf, out phThreadToken)) { hr = Marshal.GetHRForLastWin32Error(); } } else { hr = Marshal.GetHRForLastWin32Error(); } } if (hr != 0) { phThreadToken = null; } return(hr); }